A complete tutorial to learn how to develop with ERP5
('jp jp',)
ERP5 Developer Tutorial (in French)
text/html
GFDL
None
Kevin
en
None
2005-04-07 07:58:12
2005-04-07 07:57:52
()
0
Tut o r i e l N e x e d i ERP5
Développez votre propre Développez ERP grâce aux Business Templates ERP5
page 1/64
Tut o r i e l N e x e d i ERP5
page 2/64
Tut o r i e l N e x e d i ERP5
Sommaire
1. Introduction.............................................................................4 2. ERP5: un ERP pour tous............................................................5
2.1. ERP5 sans installation.......................................... .................................5 2.2. Installer un système ERP5....................................................................5 2.3. Etendre ERP5 avec les Business Templates........................................10
3. Créons notre propre Business Template !.................................16
3.1. Conception de la structure de données..............................................16 3.2. Le variantage par catégories..............................................................20 3.3. Intégrons notre structure de données dans ERP5...............................21 3.4. Web Développement rapide avec portal_classes................................22 3.5. Structure d'une classe Document dans ERP5......................................24 3.6. Créer un Module dans EPR5................................. ...............................27 3.7. Intégrer les classes, données, menus et présentation : l'outil portal_types............................................................ ...................................29 3.8. L'interface utilisateur avec ERP5Form........................................ .........30 3.9. Les scripts python de calcul....................................... .........................43 3.10. Le reporting..................................... .................................................50 3.11. La création du business template.....................................................60 3.12. Le point sur la catalogage................................................ .................62
4. Conclusion..............................................................................63 5. TODO.....................................................................................64
page 3/64
Tut o r i e l N e x e d i ERP5
1. Introduction
Cet article est destiné aux développeurs qui veulent s'approprier ERP5 et ses mécanismes pour en faire un outil de gestion d'entreprise qui répond exactement à leurs besoins. Avec ERP5, ce n'est plus l'entreprise qui se conforme à la logique ERP, c'est l'ERP qui s'adapte à la culture de l'entreprise, à ses méthodes et à ses habitudes de travail. ERP5 dispose sous forme de framework de tous les outils nécessaires pour atteindre cet objectif. Cela passe la plupart du temps par la réalisation ou la modification d'un module de l'ERP sous la forme d'un paquetage fonctionnel ou métier appelé "Business Template". Cet article vous apprendra à installer rapidement une plate-forme ERP5 grâce aux Business Template avant de vous accompagner dans la réalisation d'un module simple de gestion de feuilles de paie. Cette seconde partie de l'article sera l'occasion idéale d'aborder toutes les techniques de conception au sein d'ERP5 pour que vous puissiez par la suite créer vos propres Business Template de façon autonome.
Support Commercial ERP5 ERP5 est un ERP libre en licence GPL développé et édité par la société Nexedi. Nexedi coordonne un réseau de partenaires certifiés pour le déploiement de solutions ERP5 en entreprise. Nexedi et ses partenaires assurent à travers leurs équipes d'ingénieurs et leurs consultants l'assistance, la formation et le transfert des compétences nécessaires à la maîtrise d'ERP5 sur le terrain. http://www.erp5.org/sections/documentation/evangelism/enterprise/ Tel. +33 662 05 76 14 Mel. info@nexedi.com
page 4/64
Tut o r i e l N e x e d i ERP5
2. ERP5: un ERP pour tous
2.1. ERP5 sans installation
Si vous souhaitez utiliser ERP5 sérieusement et sans perdre du temps dans des problématiques d'installation sans valeur ajoutée, nous vous recommandons d'utiliser le LiveCD d'ERP5 (et d'y contribuer). Le LiveCD ERP5 a été conçu comme un outil de développement et de production, et pas seulement comme un démonstrateur. Il peut être téléchargé sur: http://livecd.erp5.org. Son principe est simple :
On inserre un CD dans un PC standard, on appuye sur démarrer puis, après quelques minutes, on installe des Business Template que l'on peut utiliser, paramétrer et étendre.
2.2. Installer un système ERP5
Si l'usage d'un LiveCD ne vous convient pas, il est cependant possible d'installer ERP5 de façon traditionnelle. Il faut compter entre quelques dizaines de minutes (si vous utilisez une distribution comme Mandrakelinux pour laquelle tous les paquetages et leurs dépendances ont été créés) et quelques jours (si vous utilisez une distribution sans paquetages ERP5).
page 5/64
Tut o r i e l N e x e d i ERP5
Pour fonctionner, ERP5 a besoin du serveur d'applications Zope sur lequel il se fonde et ainsi qu'un nombre conséquent de produits Zope. Nous avons aussi besoin d'installer MySQL-max (une version de la plus populaire des bases de données libres qui supporte les transactions). MySQL-max est utilisé par le moteur de recherche de Zope via le produit ZSQLcatalog. Pour un système complet, il nous faut donc :
·
un serveur Zope (et toutes ses dépendances lié à Python) comportant les optimisations développées par Nexedi en matière de méta-programmation1 les produits Zope BTreeFolder, Base18, CMF, CMFActivity, CMFCategory, CMFMailIn, CMFPhoto, CMFReportTool, ERP5, ERP5Catalog, ERP5Compatibility, ERP5Form, ERP5SyncML, ERP5Type, ExtFile, Formulator, Localizer, Photo, TranslationService, ZMailIn, ZMySQLDA et ZSQLCatalog.
MySQL-max
·
·
Pour mener à bien cette mission, il faudra compter sur les paquetages de votre distribution Linux. Vous pouvez aussi partir des sources et installer Zope par un traditionnel ./configure, make, make install. Quand aux produits Zope, ils sont très faciles et rapide à installer puisqu'il s'agit en fait d'archives à décompresser dans le répertoire Products de Zope (généralement /var/lib/zope/Products ou / usr/lib/zope/lib/python/Products) et de quelques extensions (zsqlbrain.py et InventoryBrain.py) à ajouter dans le répertoire Extensions de Zope (généralement /var/lib/zope/Extensions ou /usr/lib/zope/lib/python/Extensions). Vous trouverez sans trop de difficultés des didacticiels et de la documentation sur le net pour l'installation et la configuration globale de Zope. Les heureux utilisateurs de Mandrake peuvent se contenter d'un simple urpmi ERP5 mysql-max, après avoir ajouté les sources main, contrib et nexedi2 à leur gestionnaire de paquetages. Notons que l'ensemble des manipulations décrites dans cet article ont été réalisées sur une Mandrake 10.0 et devraient être équivalentes avec une Mandrake 10.1. Une fois l'installation le des paquetages terminée, utilisons la console d'administration de Zope, zopectl, pour changer le mot de passe par défaut de l'administrateur (le login par défaut étant admin). L'ajout d'un utilisateur ne peut se faire que si le serveur Zope est arrêté. Il se peut très bien que la procédure d'installation ait démarré le serveur, nous l' arrêterons donc avant la manipulation. Ensuite seulement nous pourrons démarrer MySQL-max et Zope :
[root@localhost /]# /etc/init.d/zope stop Arrêt de zope : . daemon process stopped
1 Le code source de ces optimisations est téléchargeable à l'URL http://www.nexedi.org/static/Mandrake/10.1/SRPMS/zope2.7.2rc1 1nxd.src.rpm 2 http://www.nexedi.org/static/Mandrake/10.1/RPMS ou http://www.nexedi.org/static/Mandrake/10.0/RPMS page 6/64
Tut o r i e l N e x e d i ERP5
[root@localhost /]# zopectl program: /usr/bin/runzope daemon manager not running zopectl> help adduser adduser <name> <password> -- add a Zope management user zopectl> adduser admin admin [root@localhost /]# /etc/init.d/mysql-max start Lancement du serveur MySQL [root@localhost /]# zopectl program: /usr/bin/runzope daemon manager not running zopectl> start daemon process started, pid=7944 [ OK ]
Il nous reste plus qu'à vérifier le fonctionnement de Zope en accédant à la ZMI, l'interface web de gestion de Zope, où l'on s'identifiera avec le mot de passe de l'utilisateur admin que l'on vient d'ajouter :
http://localhost:9080/manage
Illustration 1: L'accès à la Z MI nécessite une authentification
page 7/64
Tut o r i e l N e x e d i ERP5
Illustration 2: ZMI, l'interface web de gestion de Zope
Le serveur Zope étant désormais opérationnel et accessible, nous allons créer une instance d'ERP5 en sélectionnant le type ERP5 Site dans la liste déroulante en haut à droite :
Une page de propriétés est affichée dans la ZMI et nous la remplirons comme sur la capture d'écran :
page 8/64
Tut o r i e l N e x e d i ERP5
La validation de ce formulaire conduit à cet écran en cas de succès :
Mais il est fréquent de voir apparaître l'erreur suivante à ce moment précis :
Site Error An error was encountered while publishing this resource. Error Type: DatabaseError Error Value: z0_catalog_object is not connected to a database
Cette erreur signifie simplement que le serveur MySQL-max n'est pas démarré. Un redémarrage de ce dernier suffit pour que tout rentre dans l'ordre. On peut maintenant se rendre sur la page de garde d'ERP5 via l'url :
page 9/64
Tut o r i e l N e x e d i ERP5
http://localhost:9080/erp5/
ERP5 est maintenant opérationnel sur votre machine et se suffit à lui même pour commencer l'initiation. Je conseillerais cependant aux plus courageux de mettre à jour ERP5 depuis le CVS d'ERP53, pour pouvoir profiter des dernières évolutions et corrections de bugs. Mise en garde : bien que ERP5 soit maintenant installé et utilisable sur votre machine ou sur votre serveur, il n'est pas conseillé de l'utiliser "tel quel" en production. Une configuration fine (cluster, système d'activité, etc.) est en effet nécessaire pour obtenir des performances élevées et une réflexion sur la politique de sécurité des données est indispensable pour protéger des données vitales pour l'entreprise.
2.3. Etendre ERP5 avec les Business Templates
Les Business Templates sont à ERP5 ce que les systèmes de paquetages (rpm, apt) sont aux distributions Linux. Les RPM ont pour but de simplifier l'installation de logiciels au sein d'un système. Les Business Templates ont le même rôle en prenant en charge l'installation propre et automatisée de l'ensemble d'un module d'ERP5. D'un point de vue de l'utilisateur, installer un Business Template c'est ajouter une fonctionnalité majeure à l'ERP, en élargissant ses capacités de gestion d'entreprise. Il existe actuellement huit Business Templates, chacun étant dédié à un aspect de la gestion d'entreprise:
·
Trade : gestion commerciale (achats et ventes, commandes, bons de livraison, facturations, gestion des stocks) PDM (Product Data Management) : gestion des données produit (définition des produits, variantes, catégorisation, nomenclatures, gamme opératoire, catalogue multimédia) MRP (Manufacturing Ressources Planning) : organisation et gestion de production (ordres de fabrication, planning de production) CRM (Customer Relationship Management) : gestion des relations clientèles (base de données des organisation et des personnes, opportunités commerciales) Accounting : comptabilité (livre de comptes, rapports financiers)
·
·
·
·
3 http://cvs.erp5.org voir également le script update_cvs.sh dans /var/lib/zope/ qui permet d'automatiser les mises à jour page 10/64
Tut o r i e l N e x e d i ERP5
·
HR (Human Resources) : gestion des ressources humaines (livre de paie, gestion de carrières) eCommerce : commerce électronique (magasin de vente en ligne, affiliations) CMS (Content Management System) : gestion de contenu web (via NuxeoCPS4)
· ·
Certains de ces Business Template ont atteint un premier stade de maturité (ex. Accounting permet aujourd'hui de clôturer un exercice comptable). Les autres sont encore en cours d'intégration. En effet, bien que ERP5 soit utilisé aujourd'hui en production sur des sites importants avec une couverture fonctionnelle complète (ex. nomenclatures, gestion de production, calcul des besoins, gestion de stock, facturation, etc.), les clients d'ERP5 ne souhaitent pas pour la plupart financer le surcoût de l'intégration sous forme de Business Template générique du travail spécifique qui a été effectué pour adapter le framework ERP5 à leurs propres besoins. Le travail d'intégration des Business Template est donc effectué par Nexedi de façon bénévole. Voilà pourquoi toutes les fonctionnalités du framework ERP5 ne sont pas encore couvertes par les Business Template disponibles en téléchargement. L'un des premier module conçu qui utilise le système de Business Templates est le module de gestion de feuille de paie. Ce module permet de gérer un livre de paie et de créer des bulletins de salaire. C'est ce module qui nous servira de support tout au long de l'article. Nous allons maintenant détailler le processus d'installation de ce Business Template. Ce processus nécessite de disposer un compte avec les droits Manager. Tout convient d'accéder avec votre navigateur au module portal_templates en tapant une URL telle que http://localhost/erp5/portal_templates ou http://localhost:9480/erp5/portal_templates en fonction de votre configuration. Vous pourrez alors accéder à la liste des Business Template : d'abord, il
4 http://www.cpsproject.org/ page 11/64
Tut o r i e l N e x e d i ERP5
A titre de comparaison, un système ERP5 plus complet comporte de nombreux Business Templates :
Notre objectif est donc de passer d'une liste pratiquement vide de Business Template à une liste plus complète. Pour atteindre cet objectif, il suffit de cliquer sur le bouton "Import/Export" dans la deuxième barre de boutons à partir du haut de la page ERP5. Ce bouton ressemble à ceci :
Après avoir cliqué dessus, vous arrivez sur le dialogue d'import de Business Template :
page 12/64
Tut o r i e l N e x e d i ERP5
Utilisez alors le menu "Exchange Select" pour passer du dialogue "Import Business Template" à "Download Business Template" :
Il vous reste alors à saisir dans les deux champs, d'une part un identifiant du Business Template (ex. erp5_accounting) puis l'URL de ce Business Template (ex.
http://cvs.erp5.org/cgibin/viewcvs.cgi/*checkout*/erp5_bt5/erp5_trade.bt5?rev=HEAD&content-type=text/plain)
et à cliquer sur "Download Business Template". Le téléchargement sera effectué automatiquement (à condition d'avoir accès à Internet) et, en cas de succès, vous verrez apparaître un message "Business Template Downloaded Successfully". Vous pouvez alors cliquer sur le Business Template que vous venez de télécharger. Vous verrez alors un formulaire de définition :
page 13/64
Tut o r i e l N e x e d i ERP5
Pour procéder à l'installation, allez dans le menu "Action" et à appelez "Install Business Template"
Vous venez d'installer le Business Template de comptabilité d'ERP5. Ce module est indispensable pour le Business Template de paye. Continuons maintenant avec la paye. Le principe est le même, il faut juste importer un Business Template différent en lui donnant comme id erp5_payroll et comme URL de téléchargement http://cvs.erp5.org/cgibin/viewcvs.cgi/*checkout*/erp5_payroll/erp5_trade.bt5?rev=HEAD&contenttype=text/plain
Voici un exemple de feuille de paie généré par ce Business Template :
page 14/64
Tut o r i e l N e x e d i ERP5
Illustration 3: Une feuille de paie générée par ERP5
Pour créer cette feuille de paie, nous nous sommes basés sur un document disponible sur le site communautaire erp5.org (http://www.erp5.org/workspaces/project/erp5_payroll/erp5_pay_sheet_for_n). Ce document en anglais destiné aux débutants explique la procédure à suivre pour arriver à ses fins. Il vous aidera dans l'utilisation du module de feuille de paie. Maintenant que nous connaissons le principe des Business Template d'un point de vue utilisateur, nous pouvons entamer le coeur de cet article : la création d'un Business Template.
page 15/64
Tut o r i e l N e x e d i ERP5
3. Créons notre propre Business Template !
L'objectif de la seconde partie de cet article est d'offrir une vue d'ensemble de la plate-forme de développement ERP5 à des développeurs. Dans ce but nous allons reconstruire dans les grandes lignes le module de feuilles de paie. Cela nous donnera l'occasion de démontrer la convivialité et la puissance d'ERP5 pour la création rapide de modules fonctionnels, mais également d'approcher les technologies et les concepts qui sont à la base d'ERP5.
3.1. Conception de la structure de données
Les objets ERP5 dérivent tous de 5 classes fondamentales :
Ce modèle théorique d'EPR5 à déjà fait l'objet d'une publication scientifique5 qu'il sera intéressant de consulter pour comprendre les motivations qui se cachent derrière chacun des concepts clé d'ERP5. Nous retiendrons de ce document la description des 5 classes fondamentales :
·
Ressource
Le type Resource décrit une ressource abstraite d'un processus métier comme les compétences d'une personne, une devise, une matière première, ou un produit.
Node
·
Les objets de type Node peuvent envoyer ou recevoir des ressources. Un noeud peut représenter une entité physique (telle une machine de production, qui reçoit des matières premières, les transforment et les
5 http://www.computer.org/itpro/cover_stories/smets.htm page 16/64
Tut o r i e l N e x e d i ERP5
envoient) ou une entité abstraite (tel un compte en banque qui reçoit des sommes d'argents). Les stocks sont représentés par des noeuds. Des métanoeud (MetaNode) sont des noeuds qui contiennent d'autres noeuds. C'est le cas par exemple d'une entreprise.
·
Movement
Cette classe décrit le mouvement de ressources entre deux noeuds à un moment donné, pour un temps donné. Par exemple un mouvement peut décrire l'envoi de matière premières d'un stock vers un atelier; un mouvement peut aussi représenter l'envoi d'argent depuis un compte vers un autre.
Path
·
Un chemin décrit le moyen pour un noeud d'accéder à une ressource dont il a besoin. Des prix et des profils commerciaux peuvent être attachés à un chemin pour définir par exemple le prix par défaut d'une ressource fournit à un fabricant. Un chemin peut aussi définir la manière dont un atelier obtient ses ressources du stock. Un chemin possède des attributs de date de début et de fin, et peut représenter l'affectation d'un individu à une mission temporaire.
Item
·
Un item est une instance physique d'une quantité de ressource. Un mouvement peut se détailler en une série de mouvements traçable via des items. Les Items définissent aussi la manière dont les ressources sont livrées (selon un colis entier ou en listant les numéros de série des items dans chaque conteneur).
En analysant une feuille de paie française classique, nous avons choisis de créer 4 types d'objets :
· · · ·
PaySheetTransaction PaySheetTransactionLine PaySheetLine PaySheetCell
Voici un diagramme de classes qui donne la hiérarchie et les héritages permettant de relier les classes de bases d'ERP5 avec nos 4 nouveaux types d'objets :
page 17/64
Tut o r i e l N e x e d i ERP5
Folder
XMLObject
Movement
Delivery
DeliveryLine
DeliveryCell
Accounting Transaction
Invoice
Accounting Transaction Line
InvoiceLine
InvoiceCell
PaySheet Transaction
1
0..* Transaction
Line
PaySheet
0..*
PaySheet Line
1
0..*
PaySheet Cell
La structure de données des feuilles de paie est calquée sur le modèle de facturation (Invoice). Ce dernier est décrit par 3 classes : Invoice, InvoiceLine et InvoiceCell. Ces trois classes permettent de détailler une facture (Invoice) en lignes de facturation via InvoiceLine (une ligne de facture par produit facturé), elles mêmes décomposables selon des variantes du même produit facturé. Ainsi les InvoiceCell permettent par exemple de détailler la facturation d'une uantité de quatre produits A en trois produits A de couleur bleue et un produit A de couleur verte. Comme nous le montre le diagramme, les factures spécialisent le système de représentation des livraison (Delivery) qui implémente à l'origine la structure Line/Cell. Les cellules (Cell) sont la partie visible du concept de variantage qu'offre ERP5. Ce concept permet de représenter des variantes d'une même ressource comme la couleur, la taille ou la vitesse. Cela permet de définir plusieurs configurations d'un même produit. L'avantage de ce système réside dans la possibilité de configurer très profondément l'ERP5 tout en gardant les bénéfices d'une gestion générique des données selon une structure standardisée. Nous détaillerons le concept de variantage un peu plus loin dans cette article. Nous allons maintenant détailler nos différentes classes.
·
PaySheetTransaction
La feuille de paie en elle même est représentée par un objet de type
PaySheetTransaction.
page 18/64
Tut o r i e l N e x e d i ERP5
Cette classe dérive de la classe de base Folder via Invoice. Nous avons choisi cet héritage car les objets de type PaySheetTransaction vont nous servir à regrouper au même endroit les objets relatifs à une feuille de paie. C'est pour cela que PaySheetTransaction n'a pas comme classe ancêtre l'une des 5 classes de base d'ERP5. Folder est en quelque sorte une "classe utilitaire" qui nous permet de réduire l'entropie du système. Et comme les PaySheetTransaction sont des Folder avec des comportements particuliers dont certains sont les mêmes que pour une facture (Invoice), nous avons dû créer une nouvelle classe. Ces comportements particuliers permettront de prendre en compte la notion d'employeur et de salarié ainsi que d'autres données propres à la feuille de paie (date de paiement, salaire brut, ).
·
PaySheetLine
Comme l'indique le diagramme, chaque PaySheetTransaction peut contenir des PaySheetLine qui sont la représentation des différentes cotisations soustraite sur le salaire brut. Pour chaque cotisation il y a une et une seule PaySheetLine.
·
PaySheetCell
Les PaySheetLine contiennent les PaySheetCell, qui permettent de représenter et détailler les montants de la PaySheetLine. Le système de variantage permettra de distinguer les parts employeur et employée d'une cotisation sociale donnée et de conserver une trace de la méthode de calcul des montants. Car pour une cotisation donnée, le montant d'une part (salariale ou patronale) peut être le fruit d'un savant calcul faisant intervenir un ou plusieurs taux, associé chacun à une assiette (salaire brut, salaire plafonné, salaire tranche A/B/C, ). Le calcul des feuilles de paie n'est pas évident, d'autant plus que la législation change tout les jours Le variantage offre un avantage de taille dans ce cas car il permet de parer à toutes les complications induites par la législation de chaque pays.
·
PaySheetTransactionLine
Les PaySheetTransactionLine sont la représentation comptable de la feuille de paie. Nous avons choisi de distinguer les PaySheetLine et les PaySheetTransactionLine car la représentation de la feuille de paie selon la logique comptable agrège certains montants et rend impossible un reporting fin sur la paye. Nous avons donc au sein d'une PaySheetTransaction deux ensembles :
·
Les données du couple PaySheetLine/PaySheetCell : un jeu de données de
page 19/64
Tut o r i e l N e x e d i ERP5
base qui nous permet d'afficher les détails de la feuille de paie et de manipuler les chiffres dans tous les sens.
·
Les données de type PaySheetTransactionLine, qui représentent les lignes comptable de la feuille de paie
Maintenant que nous avons un modèle de données cohérent, nous allons l'implémenter dans ERP5.
3.2. Le variantage par catégories
Les objets de type Category sont utilisés dans ERP5 pour la classification. Par exemple, un document peut posséder un attribut couleur. Au lieu de laisser l'utilisateur entrer une valeur libre, via un champ texte, pour l'attribut couleur, on préférera attribuer à l'objet une catégorie. On fabriquera donc via la ZMI les catégories couleur/bleu, couleur/vert et couleur/rouge :
Les catégories peuvent contenir des sous-catégories. Par exemple pour décrire les régions géographiques :
region/europe region/europe/west/ region/europe/west/france region/europe/west/germany region/europe/south/spain region/americas region/americas/north region/americas/north/us
page 20/64
Tut o r i e l N e x e d i ERP5
region/americas/south region/asia
Dans cet exemple la catégorie de base est region. Les catégories ont d'autres avantages comme le catalogage automatique. Ce mécanisme rend possible l'utilisation de requêtes SQL pour sélectionner les objets de la ZODB selon la valeur de la catégorie (voir plus bas paragraphe : catalogage). Il est possible de créer des classifications "virtuelles" basée sur des documents existant ou sur des catégories. Par exemple, si un document est accessible à au chemin organisation/nexedi, et qu'il existe une catégorie de base client, l'outil portal_categories autorise la création de la catégorie virtuelle client/organisation/nexedi. Cela permet de représenter un lien relationnel selon le schéma : « le client de tel objet est l'organisation Nexedi ». Le concept de la virtualisation des catégories évite la duplication des informations en offrant des mécanismes équivalent à une base de donnée relationnelle.
3.3. Intégrons notre structure de données dans ERP5
Nous allons ajouter dans ERP5 toutes les classes d'objets que nous avons définies dans le paragraphe précédent. ERP5 possède des mécanismes propres pour définir de nouvelles classes d'objets, ce qui lui permet de prendre en charge la création dynamique et automatisée de méthodes. Le travail de création de nouvelles classes se limite donc à les décrire, ERP5 se chargera du reste, comme la création dynamique des "setter" et "getter". Les classes d'objets se définissent via un script python dans le dossier Document de l'instance Zope/ERP5. Nous allons créer une nouvelle classe PaySheetTransaction, et pour éviter de ressaisir tout le code, faire une copie du fichier Invoice.py que nous éditerons :
[root@localhost /]# cd /usr/lib/zope/lib/python/Products/ERP5/Document/ [root@localhost Document]# cp Invoice.py / var/lib/zope/Document/PaySheetTransaction.py [root@localhost Document]# vi /var/lib/zope/Document/PaySheetTransaction.py () [root@localhost Document]# chown zope:zope / var/lib/zope/Document/PaySheetTransaction.py [root@localhost Document]# chmod 755 / var/lib/zope/Document/PaySheetTransaction.py
Voici ce à quoi doit ressembler le fichier PaySheetTransaction.py après édition :
page 21/64
Tut o r i e l N e x e d i ERP5
from AccessControl import ClassSecurityInfo from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface from Products.ERP5.Document.Invoice import Invoice class PaySheetTransaction(Invoice): """ A paysheet will store data about the salary of an employee """ meta_type = 'ERP5 Pay Sheet Transaction' portal_type = 'Pay Sheet Transaction' add_permission = Permissions.AddPortalContent isPortalContent = 1 isRADContent = 1 # Declarative security security = ClassSecurityInfo() security.declareObjectProtected(Permissions.View) # Default Properties property_sheets = ( PropertySheet.Base , PropertySheet.SimpleItem , PropertySheet.CategoryCore , PropertySheet.Task , PropertySheet.Arrow , PropertySheet.Delivery , PropertySheet.Movement , PropertySheet.Amount , PropertySheet.XMLObject , PropertySheet.PaySheetTransaction ) # Declarative Interface __implements__ = ( )
3.4. Web Développement rapide avec portal_classes
Il est possible de réaliser l'ensemble des opérations de création de classes ou d'édition du code via l'interface Web d'ERP5 grâce à l'outil portal_classes :
page 22/64
Tut o r i e l N e x e d i ERP5
L'édition de code python d'une classe ERP5 permet également de recharger à chaud le seul code modifié, sans redémarrer Zope et de gagner en productivité.
L'outil portal_classes est très utile en phase de prototypage ou de développement rapide. Il facilite également l'apprentissage d'ERP5. Il est cependant déconseillé de l'activer sur un système en production car il comporte des risques élevés en matière de sécurité. Aussi est-il désactivé par défaut dans le LiveCD ERP5 ou dans les paquetages ERP5 pour Mandrakelinux. Pour l'activer, il est donc nécessaire de créer un fichier vide ALLOW_CLASS_TOOL dans le répertoir du produit ERP5Type.
page 23/64
Tut o r i e l N e x e d i ERP5
3.5. Structure d'une classe Document dans ERP5
Les fichiers de type Document ont généralement la même allure, et les valeurs propres à notre nouvelle classe se devinent facilement. Toujours dans le dossier de l'instance Zope/ERP5, PropertySheet sert à contenir des scripts python similaires à ceux que l'on trouve dans le dossier PropertySheet du produit ERP5. Ces scripts aux noms évocateurs permettent de définir des attributs de classes et, par extension, le schéma de données d'ERP5. Les classes y font souvent référence grâce à la liste property_sheets, comme on peut le voir dans le code python précédent. Ainsi pour que chaque feuille de paye puisse stocker le salaire brut ("gross salary" en anglais), nous avons fait référence à la property sheet PaySheetTransaction qui contiendra la définition de l'attribut gross_salary de type flottant. Il nous faut maintenant la créer :
[root@localhost [root@localhost [root@localhost () [root@localhost [root@localhost /]# cd /var/lib/zope/PropertySheet/ PropertySheet]# touch PaySheetTransaction.py PropertySheet]# vi PaySheetTransaction.py PropertySheet]# chown zope:zope PaySheetTransaction.py PropertySheet]# chmod 755 PaySheetTransaction.py
Voici le contenu de la property sheet PaySheetTransaction.py :
class PaySheetTransaction: """ Properties for PaySheet Transaction objects """ _properties = ( { 'id' , 'description' paysheet' , 'type' , 'mode' }, ) _categories = ( , , , ) : 'gross_salary' : 'This variable contain the gross salary of the : 'float' : 'w'
'source' 'destination' 'source_section' 'destination_section'
La syntaxe est assez intuitive car tous les attributs se déclarent par une liste de dictionnaires python dans la variable _properties. Il convient juste de faire attention aux listes immuables (tuple) à un élement en python et à ne pas oublier la virgule avant la parenthèse de fin.
page 24/64
Tut o r i e l N e x e d i ERP5
[kevin@localhost Products]$ python Python 2.3.3 (#2, Feb 17 2004, 11:45:40) [GCC 3.3.2 (Mandrake Linux 10.0 3.3.2-6mdk)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> (5) 5 >>> (5,) (5,) >>> (5,10) (5, 10) >>>
Ainsi (5) est interprété comme l'entier 5, et (5,) comme une liste immuable contenant un seul élément entier égal à 5. La liste _categories contient la liste des catégories virtuelles. Nous utiliserons celles-ci pour créer un lien entre la feuille de paie, l'employeur et le salarié. La relation source_section fera référence à l'employeur (qui est l'organisation ou l'entreprise qui émet la feuille de paie) et la relation destination_section fera référence au salarié (la personne à qui se destine la feuille de paie). Si plus tard nous avons besoin de définir des attributs plus complexes, nous nous inspirerons des PropertySheets pré-existante dans le produit ERP5. Cette méthode est valable pour tous les points abordé dans cet article : puisque le code source est ouvert, il ne faut pas se priver de réutiliser ou de s'inspirer de choses existantes pour construire petit à petit des choses nouvelles. C'est même un obligation pour contribuer au code d'ERP5 : deux propriétés similaires doivent, par principe, avoir le même nom dans ERP5. Maintenant que notre nouvelle classe est construite, il est nécessaire soit de recharger son code (avec portal_classes sur la classe de PropertySheet puis sur la classe de Document) soit de redémarrer le serveur Zope pour qu'il puisse les prendre en compte. Si tout ce passe bien le serveur sera disponible et vous pourrez accéder à la ZMI :
[root@localhost kevin]# zopectl program: /usr/bin/runzope program running; pid=4450 zopectl> restart . daemon process restarted, pid=4773 zopectl> logtail -----2004-05-12T18:50:03 INFO(0) Z2 Caught signal SIGTERM -----2004-05-12T18:50:03 INFO(0) Z2 Shutting down fast -----2004-05-12T18:50:03 INFO(0) ZServer closing HTTP to new connections -----2004-05-12T18:50:03 INFO(0) ZServer closing FTP to new connections -----page 25/64
Tut o r i e l N e x e d i ERP5
2004-05-12T18:50:03 INFO(0) Zope Shutting down with exit code 0 () -----2004-05-12T18:50:42 INFO(0) Zope Ready to handle requests zopectl>
Il est possible qu'au moment du redémarrage, Zope s'arrête et refuse obstinément de démarrer. Il est aussi possible d'observer un comportement étrange de Zope : l'arrêt et le démarrage en boucle du serveur par périodes de 10 secondes. Les causes de ce blocage sont liées dans la majorité des ca à de mauvaises permissions sur les scripts ou à une mauvaise attribution de la propriété des fichiers que vous venez de créer. Une série de chmod et chown réglera ce problème. Si malgré ces corrections le problème persiste, il zopectl intègre une commande debug, qui lorsqu'on l'appelle va arrêter le serveur et le démarrer en vous affichant le log de démarrage et un rapport d'exécution (traceback) en cas d'erreur. Par exemple :
[root@localhost kevin]# zopectl program: /usr/bin/runzope daemon manager not running zopectl> debug Starting debugger (the name "app" is bound to the top-level Zope object) () Traceback (most recent call last): File "<string>", line 1, in ? File "/usr/lib/python2.3/site-packages/PIL/__init__.py", line 50, in app File "/usr/lib/python2.3/site-packages/PIL/__init__.py", line 46, in startup File "/usr/lib/zope/./build/build-base/python-2.3/buildlib/Zope/App/startup.py", line 45, in startup File "/usr/lib/zope/./build/build-base/python-2.3/buildlib/OFS/Application.py", line 631, in import_products File "/usr/lib/zope/./build/build-base/python-2.3/buildlib/OFS/Application.py", line 654, in import_product File "/usr/lib/zope/lib/python/Products/ERP5/__init__.py", line 50, in ? from Tool import Category, CategoryTool, SimulationTool, RuleTool, IdTool, TemplateTool, TestTool File "/usr/lib/zope/lib/python/Products/ERP5/Tool/Category.py", line 35, in ? from Products.ERP5.Document.MetaNode import MetaNode File "/usr/lib/zope/lib/python/Products/ERP5/Document/__init__.py", line 3145, in ? import PaySheetTransaction as ERP5PaySheetTransaction File "/usr/lib/zope/lib/python/Products/ERP5/Document/PaySheetTransaction.py", line 62
page 26/64
Tut o r i e l N e x e d i ERP5
__implements__ = ( ) ^ SyntaxError: invalid syntax >>>
Le traceback nous apprend qu'il y a une erreur invalid syntax dans le fichier / usr/lib/zope/lib/python/Products/ERP5/Document/PaySheetTransaction.py, ligne 62. En éditant le dit fichier on s'aperçoit en fait que le malheureux développeur a oublié de fermer la liste property_sheets avec une parenthèse. Il nous suffira dans ce cas que d'une petite correction pour pouvoir relancer le serveur zope Attention : pour utiliser la commande debug il ne faut pas oublier de mettre à on l'option debug-mode du fichier /etc/zope.conf. Il n'est d'ailleurs pas surprenant de devoir utiliser debug 30 fois par jour lorsque l'on débute et que l'on ne maîtrise pas la syntaxe de python, ou lorsque l'on travaille sur le CVS d'un projet ERP5 en équipe et que des conflits surgissent. Selon le même principe nous avons construit les nouveaux types
PaySheetTransactionLine, PaySheetLine et PaySheetCell. Par curiosité on pourra
aller consulter les classes pythons qui les définissent :
[root@localhost [root@localhost [root@localhost [root@localhost /]# cd /usr/lib/zope/lib/python/Products/ERP5/Document/ Document]# vi PaySheetTransactionLine.py Document]# vi PaySheetLine.py Document]# vi PaySheetCell.py
Le lecteur attentif aura sans doute remarqué ici que le code du module de paye est parfois situé dans le dossier /usr/lib/zope/lib/python/Products/ERP5/Document/ et parfois dans le dossier /var/lib/zope/Document. Une explication s'impose. Le dossier /var/lib/zope/Document est conçu pour le développement rapide de code d'extension au framework ERP5. C'est donc bien dans ce dossier qu'il faut commencer à travailler lorsque l'on conçoit un nouveau jeu de classes pour un client ou pour une future extension d'ERP5. Si ce jeu de classes semble suffisamment générique et susceptible de correspondre à une fonction universelle d'un ERP, il est conseillé de l'intégrer au projet ERP5 afin de le partager avec l'ensemble de la communauté. C'est bien le cas de la paye. En revanche, si ce jeu de classes est lié à un métier ou aux besoins spécifiques d'une entreprise, il n'y a aucune raison de l'intégrer au coeur d'ERP5. La paye faisant désormais partie du coeur d'ERP5, il nous arrivera souvent de mentionner des fichiers situés dans le dossier Document du produit ERP5. Cependant, pour les besoins du tutoriel, nous créerons tous les nouvelles classes dans les dossiers de l'instance Zope/ERP5, c'est-à-dire généralement /var/lib/zope.
3.6. Créer un Module dans EPR5
Lors de l'introduction de ce chapitre nous avons fait l'amalgame entre les
page 27/64
Tut o r i e l N e x e d i ERP5
Business Templates et les modules de l'ERP. Nous allons maintenant faire la différence et décrire plus précisément le rôle d'un module, au sens d'ERP5, puis en créer un. Un module est simplement un lieu dans l'interface utilisateur d'ERP5 ou se rassemblent les fonctionnalités propres à un aspect de la gestion d'entreprise. Le Business Template contient tous les scripts et objets qui permettent de faire fonctionner le module. D'où l'amalgame. La création rapide d'un nouveau module peut être effectuée en allant à l'URL :
http://localhost:9480/erp5/ERP5Site_viewCreateModuleDialog
où apparaît le dialogue suivant :
Ce dialogue comporte 6 paramètres :
· · · · · ·
Module Id : l'id du dossier (Folder) créé à la racine du site ERP5 et qui contiendra l'ensemble des feuilles de paye. Module Portal Type : le nom du type documentaire qui sera créé pour contenir toutes les feuilles de paye Module Title : le titre qui apparaîtra dans le menu modules pour le module de paye Object Portal Type : le nom du type documentaire qui sera créé pour définir les feuilles de paye Object Title : le titre qui apparaîtra par défaut pour chaque feuille de paye Portal Skins Folder : le dossier dans lequel seront créés les formulaires par défaut
En cliquant sur "Create Module", tous les types documentaires sont
page 28/64
Tut o r i e l N e x e d i ERP5
automatiquement créés et les menus mis à jour. Un module de paye "vide" vient d'être créé. Il s'agit désormais de le paramétrer.
3.7. Intégrer les classes, données, menus et présentation : l'outil portal_types
ERP5 est conçu autour de l'architecture Zope/CMF. L'une des caractéristiques du CMF est le concept d'outil (tool en anglais) placé à la racine d'un portail et conçu pour fournir divers services : traduction de formats de documents, gestion des menus associés à un document, internationalisation, synchronisation, etc. L'outil portal_types permet de créer des types génériques de document sur la base de nos classes définies dans la partie précédente et de leur associer des menus ainsi que des éléments de présentation. Nous ferons la distinction par la suite entre portal_types (l'outil) et les portal types (les types de document définis par l'outil portal_types). Le contenu de l'outil portal_types correspond aux modules et aux types documentaires disponibles dans l'instance ERP5.
Pour résumer on peut dire que tous nos portal types du genre PaySheet* sont des images dans Zope de nos classes définies par nos scripts python. La réalité est plus subtile car ils peut y avoir deux portal types différents qui se basent sur la même classe, car leur rôle premier est de créer des types
page 29/64
Tut o r i e l N e x e d i ERP5
documentaires. Par exemple depuis une même classe DocumentEcrit nous pouvons créer deux portal types différents : Article et CommuniquéDePresse. Les deux se décrivent par la même structure de données et les mêmes propriétés. L'intérêt de créer deux types de documents est que nous pouvons appliquer à chaque type un workflow différent ou une mise en page adaptée.
3.8. L'interface utilisateur avec ERP5Form
Nous allons exploiter ici les capacités de RAD (environnement de développement rapide) d'ERP5 via le produit ERP5Form, afin de définir l'interface utilisateur de notre module. ERP5Form est le générateur de formulaires d'ERP5. Il est dérivé de Formulator, un produit Zope créé par Infrae. Lorsque nous allons dans le module de paye, nous pouvons ajouter des PaySheetTransaction :
Cependant, notre action se termine sur une erreur :
page 30/64
Tut o r i e l N e x e d i ERP5
Or, la méthode de création d'une nouvelle feuille de paie à bien fonctionné comme l'atteste la présence dans la ZODB d'une nouvelle instance du portal type Pay Sheet Transaction qui à été créée dans le dossier paysheet du module :
Il ne s'agit donc que d'un problème de présentation. Pour le résoudre, nous devons ajouter une interface utilisateur à la feuille de paie pour que l'action de création n'aboutisse pas sur une erreur lorsque elle tente d'afficher l'objet créé. Nous allons donc créer un nouveau formulaire. Comme tous les formulaires et les autres objets de présentation, ils sont définis dans des sous-dossiers de l'outil portal_skins. Allons par exemple dans le dossier /erp5/portal_skins/local_erp5.
page 31/64
Tut o r i e l N e x e d i ERP5
Un formulaire se crée comme n'importe quel objet zope via la ZMI : il suffit de choisir le type "ERP5 Form". Appelons notre formulaire PaySheetTransaction_view :
Commençons pour l'éditer par lui ajouter un champ de type float pour représenter le salaire brut :
Pour indiquer implicitement que ce champ correspond à l'attribut gross_salary de notre objet, il suffit de le nommer my_gross_salary :
page 32/64
Tut o r i e l N e x e d i ERP5
L'utilisation du préfixe my_ est une des règles de nommage propre à ERP5. Si un champ de formulaire est nommé my_quelque_chose, il affichera par défaut une valeur obtenue en appelant la méthode getQuelqueChose sur le document auquel il est appliqué. En cas de validation du formulaire, la méthode setQuelqueChose sera appelée sur le document auquel le formulaire a été appliqué pour mettre à jour la valeur de la propriété quelque_chose. Pour être complet, il faut également configurer le formulaire pour que le salaire brut puisse être modifié en définissant la propriété Form action comme sur la capture d'écran :
L'action "Base_edit" est appelée lorsque l'on valide le formulaire et prend en compte les données saisies par l'utilisateur pour mettre à jour le document auquel le formulaire est appliqué. Pour tester que notre formulaire fonctionne, appelons directement depuis l'url :
page 33/64
Tut o r i e l N e x e d i ERP5
http://localhost:9080/erp5/paysheet/1/PaySheetTransaction_view
Afin que ce formulaire soit utilisé par défaut pout afficher les feuilles de paie, retournons dans l'outil portal_types. Allons dans l'onglet action du portal type correspondant à la feuille de paie. On peut alors définir une nouvelle action :
Le choix de la catégorie "object_view" Le choix de l'id "view" correspond à nous ajoutons une nouvelle feuille de module de paye, le formulaire va information de salaire brut :
correspond à la notion d'onglet dans ERP5. l'affichage par défaut. Désormais, lorsque paie depuis le menu déroulant Actions du être automatiquement affiché avec une
Notons ici que les deux URL :
http://localhost:9080/erp5/paysheet/2/view
et
http://localhost:9080/erp5/paysheet/2/PaySheetTransaction_view
page 34/64
Tut o r i e l N e x e d i ERP5
donnent le même résultat en raison de l'association de PaySheetTransaction_view à l'id view dans les actions du portal_type. Il peut être intéressant à ce stade de tester quelques URL typiques d'ERP5 afin de bien comprendre la notion d'accesseur. Par exemple, le fait d'avoir défini dans la PropertySheet de feuille de paye une propriété "gross_salary" a entrainé la génération automatique par ERP5 d'une méthode "getGrossSalary". Cette méthode peut être testée directement en appelant une URL adéquate sur la feuille de paye :
http://localhost:9080/erp5/paysheet/2/getGrossSalary
Cette URL affiche dans le navigateur la valeur de forme de chaîne de caractère.
gross_salary convertie sous
En utilisant les propriétés du formulaire et des champs qui le constituent, on peu obtenir rapidement un formulaire plus développé et plus utile. On commence par ajouter des champs pour chaque propriété que l'on souhaite gérer avec le formulaire :
Illustration 4: De nouveaux champs pour chaque attribut de l'objet
L'onglet "Order" permet de regrouper les champs et définir leur présentation :
page 35/64
Tut o r i e l N e x e d i ERP5
Illustration 5: Utilisation de groupes pour la représentation du formulaire
Le style ERP5 par défaut utilise 4 groupes : left (ou Default), right, center et bottom. Nous n'avons pour l'instant utilisé que les deux premiers groupes qui se traduisent par un affichage sur 2 colonnes :
Illustration 6: Le formulaire vu par l'utilisateur
Ajoutons maintenant deux champs qui permettent d'associer la feuille de paie à l'employeur et au salarié. Avant cela il est indispensable d'installer le Business Template CRM, qui permet de gérer les personnes et les organisations, en suivant la méthode expliquée en première partie. Une fois installé, nous pouvons nous occuper des relations.
page 36/64
Tut o r i e l N e x e d i ERP5
Les champs à ajouter sont de type RelationStringField :
Nous ajouterons deux champs de ce type, my_destination_section_title permettra de saisir le salarié à qui la feuille de paie est destinée et my_source_section_title l'employeur qui émet la feuille de paie :
page 37/64
Tut o r i e l N e x e d i ERP5
Il faut ensuite modifier les propriétés des deux widgets pour qu'ils puissent fonctionner :
Comme on peut le deviner avec les captures précédentes, Base Category permet d'indiquer la catégorie de base sur laquelle la relation s'appuie. Souvenez-vous également que cette catégorie à été explicitement déclarée dans la property sheet adéquate, justement pour pouvoir être utilisée à cet endroit. La relation d'employeur est maintenant définissable par une catégorie virtuelle de la forme source_section/organisation/nexedi. On peut vérifier la bonne intégration des données en appelant directement le getter de l'attribut sur l'objet, et ce depuis l'url :
http://localhost:9080/erp5/paysheet/2/getSourceSection
Pour comprendre comment ces informations sont gérées par ERP5, il peut être utile d'appeler la méthode Base_viewDict qui permet d'inspecter le contenu des objets enregistrés dans la ZODB :
http://localhost:9080/erp5/paysheet/2/Base_viewDict
La propriété Portal Type de ce type de widget permet quand à elle de spécifier les types d'objets qui seront acceptés comme relation par le champ. On retrouvera cette propriété dans différents widgets du produit Formulator. Ensuite, la valeur à donner aux autres propriétés de ce type de champ sont assez intuitives.
page 38/64
Tut o r i e l N e x e d i ERP5
Nous nous retrouvons ainsi avec un formulaire qui se rapproche de sa forme finale :
De
existe une action view reliée au formulaire PaySheetTransaction_view définie dans le portal type Pay Sheet Transaction, il existe une action view sur le portal type du module qui par défaut est Folder_list :
même
qu'il
Nous allons créer notre propre formulaire PaySheetModule_view qui va nous servir à l'affichage par défaut du contenu du module. Pour cela il nous faut changer les actions du module et créer un nouveau formulaire :
page 39/64
Tut o r i e l N e x e d i ERP5
Ce formulaire n'a besoin de contenir qu'un seul widget de type ListBox :
page 40/64
Tut o r i e l N e x e d i ERP5
Toujours par convention, nous l'appellerons listbox. Les List Box sont très flexibles et nous allons les utiliser pour afficher un résumé du contenu du module de feuille de paie. La capture d'écran suivante vous montre les propriétés de la List Box :
D'un point de vue utilisateur, ce formulaire aura le look suivant :
page 41/64
Tut o r i e l N e x e d i ERP5
Les propriétés importantes d'une List Box sont List Action et List Method. Cette dernière prend la valeur portal_catalog, pour indiquer que la méthode utilisée pour la génération de la liste se base sur le catalogue. La propriété Colum,s permet de définir l'ordre et les données des colonnes de la liste. Le reste des propriétés permet de gérer un comportement avancé de la liste, comme le tri, la sélection de lignes, le filtrage, etc. Nous ne nous attarderons pas dessus, et je vous laisse le soin d'explorer les possibilités offertes par ERP5Form. Cela devrait être assez facile car les noms des propriétés sont assez transparents et peuvent être compris par des tests et essais.
page 42/64
Tut o r i e l N e x e d i ERP5
3.9. Les scripts python de calcul
L'étape suivante consiste à créer un script qui, depuis le salaire brut, produit toutes les données de la feuille de paie. Pour cela nous créons un nouveau script python que nous nommerons PaySheetTransaction_calcul :
Nous mettons également à jour les actions du portal type des Pay Sheet Transaction pour qu'il prenne en compte notre script :
page 43/64
Tut o r i e l N e x e d i ERP5
En donnant la valeur object_action à l'attribut Category, on ajoute une entrée dans le menu d'action de la vue des Pay Sheet Transaction :
Le script étant vide, il ne va forcement rien se passer si on sélectionne Calcul dans la liste des actions. Maintenant il va nous falloir coder le script pour qu'il : · récupère les données suffisante (salaire brut, employeur, etc), · calcule les taux et les assiettes et · distribue les montants selon les bonnes catégories et aux bons organismes sociaux. Les points 1 et 2 ne nécessitent pas d'explication particulières, en dehors de la connaissance fine de la méthode de calcul des montants. Nous allons à ce propos simplement générer quelques lignes de feuilles de paies à titre d'exemple. Le troisième et dernier point requiert quelques explications. Nous allons détailler le comportement de la Structure PaySheetLine / PaySheetCell du point de vue du développeur. Les cellules peuvent être représentées comme des tableaux ou des matrices repérées par deux catégories de base : assiette et categorie_taxe. Pour illustrer notre propos, prenons l'assurance vieillesse (les taux sont ceux d'avril 2003). La part salariale est égale à la valeur du salaire plafonné multipliée par 6.55%. La part patronale est égale à la somme de 1.60% du salaire brut et de 8.20% du salaire plafonné. Voici la représentation de ces chiffres au sein de la PaySheetLine pour un salaire de 3000 euros :
page 44/64
Tut o r i e l N e x e d i ERP5
Les objets sont identifiés par un cadre rouge et leurs attributs les plus significatifs sont notés à l'intérieur. La cotisation "Assurance vieillesse" est représente par une PaySheetLine qui contient une matrice de 4 cellules de type PaySheetCell. Puisque les catégories et les catégories de base se définissent au niveau de la PaySheetLine, cette dernière va être capable de générer automatiquement le tableau de cellules à sa création. De ce fait nous n'avons plus qu'à choisir notre cellule selon les catégories et lui affecter ses valeurs. Une cellule possède deux attributs : quantity et price. quantity représente l'assiette et price le taux. Pour calculer le montant, il suffit d'invoquer getTotalPrice() qui effectuera la multiplication quantity * price. L'assurance vieillesse est une sous-partie des cotisations de sécurité sociale, et pour représenter cette hiérarchie nous avons créé la sous catégorie secu. Cette dernière se subdivise en part salariale et en part employeur pour répartir finement les montants. Puisque l'assurance vieillesse est calculée à partir du salaire brut et du salaire plafonné, nous avons créé les sous-catégories correspondantes dans la catégorie de base assiette. Une bonne définition des catégories nous permettras par la suite de générer facilement des rapports détaillés. Puisque dans le script nous allons générer les cotisations d'assurance maladie, d'assurance vieillesse et d'assurance chômage, voici les catégories que nous avons ajoutées dans l'outil portal_category :
categorie_taxe categorie_taxe/secu categorie_taxe/secu/part_employeur categorie_taxe/secu/part_salariale categorie_taxe/chomage categorie_taxe/chomage/part_employeur categorie_taxe/chomage/part_salariale
page 45/64
Tut o r i e l N e x e d i ERP5
assiette assiette/salaire_brut assiette/salaire_plafonne assiette/tranche_a assiette/tranche_b assiette/tranche_c
Voici donc le script python qui générera les quelques lignes de feuilles de paie :
# Ce script est donné à titre d'exemple # Les constantes ont été codées en dur pour faciliter la lecture global paysheet paysheet paysheet_type paysheet_cell_type paysheet_transactionline_type = = = = context.getObject() paysheet.getPortalType() 'Pay Sheet Cell' 'Pay Sheet Transaction Line'
employer = paysheet.getSourceSection() employee = paysheet.getDestinationSection() if employer in ('', None): return context.REQUEST.RESPONSE.redirect(context.absolute_url() + '?portal_status_message=The+employer+is+required') if employee in ('', None): return context.REQUEST.RESPONSE.redirect(context.absolute_url() + '?portal_status_message=The+employee+is+required') employer_object = paysheet.getSourceSectionValue() if employer_obj.getDefaultAddress().getZipCode() in ('', None): return context.REQUEST.RESPONSE.redirect(context.absolute_url() + '?portal_status_message=The+employer+must+have+a+zip+code') gross_salary = abs(paysheet.getGrossSalary()) employer_region = employer_object.getDefaultAddress().getZipCode()[:2] # limited salary = salaire plafonné if gross_salary < 2432: limited_salary = gross_salary else: limited_salary = 2432 # "Char" slice type if gross_salary <= 2432: char_slice = 'A' elif gross_salary <= 9728: char_slice = 'B' elif gross_salary <= 19456:
page 46/64
Tut o r i e l N e x e d i ERP5
char_slice = 'C' else: char_slice = '' ######################################################################### # This part of the script implement functions to register all pay sheet # informations from an ERP5 point of view. ######################################################################### def createPaySheetItem(title='', dest_org='', cells=[]): global paysheet # get all variation categories used in cells var_cat_list = [] for cell in cells: var_cat_list.append(cell["x"]) var_cat_list.append(cell["y"]) # add a new Pay Sheet Line payline = paysheet.newContent( portal_type = 'Pay Sheet Line' , title = title , destination = dest_org , variation_base_category_list = ('tax_category', 'salary_range') , variation_category_list = var_cat_list ) # fill each cell with values for cell in cells: paycell = payline.getCell(cell["x"], cell["y"], base_id = 'movement') paycell.edit(quantity=-cell["base"], price=cell["rate"]/100.0) ######################################################################### # This part of script describe the behaviour of the calculation process # from accountant point of view. ######################################################################### # social organism org_urssaf = 'organisation/urssaf' org_assedic = 'organisation/assedic' # variation categories cat_social_salary_share cat_social_employer_share cat_unemployment_salary_share cat_unemployment_employer_share cat_gross_salary cat_limited_salary cat_slice_a cat_slice_b cat_slice_c = = = = = = = = = 'tax_category/social/salary_share' 'tax_category/social/employer_share' 'tax_category/unemployment/salary_share' 'tax_category/unemployment/employer_share' 'salary_range/france/salaire_brut' 'salary_range/france/salaire_plafonne' 'salary_range/france/tranche_a' 'salary_range/france/tranche_b' 'salary_range/france/tranche_c'
# sickness insurance = assurance maladie if employer_region in ('57', '67', '68'):
page 47/64
Tut o r i e l N e x e d i ERP5
salary_share_rate else: salary_share_rate createPaySheetItem( , ,
= 1.70 = 0.75 title = 'Assurance maladie' dest_org = org_urssaf cells = [ { "x" : cat_social_salary_share , "y" : cat_gross_salary , "base" : gross_salary , "rate" : salary_share_rate }, { "x" : cat_social_employer_share , "y" : cat_gross_salary , "base" : gross_salary , "rate" : 12.80 } ] = assurance vieillesse title = 'Assurance vieillesse' dest_org = org_urssaf cells = [ { "x" : cat_social_salary_share , "y" : cat_limited_salary , "base" : limited_salary , "rate" : 6.55 }, { "x" : cat_social_employer_share , "y" : cat_gross_salary , "base" : gross_salary , "rate" : 1.60 }, { "x" : cat_social_employer_share , "y" : cat_limited_salary , "base" : limited_salary , "rate" : 8.20 } ]
) # old-age insurance createPaySheetItem( , ,
) # unemployment insurance = assurance chomage if char_slice in ('A', 'B'): if char_slice == 'A': cat_slice = cat_slice_a else: cat_slice = cat_slice_b createPaySheetItem( title = 'Assurance chomage' , dest_org = org_assedic , cells = [ { "x" : cat_unemployment_salary_share , "y" : cat_slice , "base" : gross_salary , "rate" : 2.4 }, { "x" : cat_unemployment_employer_share , "y" : cat_slice
page 48/64
Tut o r i e l N e x e d i ERP5
, "base" : gross_salary , "rate" : 4.0 } ] )
Si votre éditeur préféré supporte le protocole WebDAV, n'oubliez pas que Zope le supporte également. En dé-commentant quelques lignes dans le fichier / etc/zope.conf et après un redémarrage de Zope, WebDAV sera activé et vous pourrez naviguer au sein de la ZODB puis éditer très facilement des script python dans votre environnement de développement favori.
Illustration 7: Utilisation de WebDAV avec KATE
Avant de tester le script, n'oublier pas de créer les organisations Assedic et Urssaf avec le même id qui est utilisé dans le script (organisation/urssaf et organisation/assedic) pour qu'il puisse fonctionner.
page 49/64
Tut o r i e l N e x e d i ERP5
3.10. Le reporting
Nous allons voir dans cette partie comment utiliser les données générées par notre script pour créer des rapports et les versions imprimable des feuilles de paie. Ces dernières seront produites au travers d'une Page Template que l'on créera dans local_erp5 sous le nom de PaySheetTransaction_print :
Les page templates ne sont en fait que de simples fichiers html (ou xml) dans lesquels nous allons utiliser des attributs spéciaux dans les balises. Ce langage nommé TAL (Template Attribute Language) propre à Zope permet de décrire un comportement dynamique des pages. ERP5 intégre d'ailleurs un script qui permet de convertir automatiquement un document OpenOffice en TAL afin de faciliter la création rapide de rapports PDF. Dans le cas de notre feuille de paie, nous allons créer un script python qui va se charger de pré-formater les données de la feuille de paie et nous allons l'appeler depuis la Page Template. Le script, que nous appellerons PaySheetTransaction_getDetails, va se charger essentiellement de collecter les part patronale et salariale pour chacune des taxe et les rassembler dans un dictionnaire :
# this dict contain all paysheet details
page 50/64
Tut o r i e l N e x e d i ERP5
paysheet_details = {} # initialize the employee and total_employee_share total_employer_share total_taxable_employee_share employer share total = 0.0 = 0.0 = 0.0
# get the gross salary gross_salary = context.getGrossSalary() if gross_salary == None: gross_salary = 0.0 paysheet_cat = {} object_list = [] for object in context.objectValues(): object_list += [object] # Sort the list by id since lines are already ordered by id. object_list.sort(lambda x, y: cmp(int(x.getId()), int(y.getId()))) for pay_sheet_line in object_list: variation_list = pay_sheet_line.getVariationCategoryList() range_variation = [] for variation in variation_list: if variation.find('salary_range')==0: if not variation in range_variation: # Extra checking because # get VariationCategoryList returns # the same 1 items 2 times range_variation += [variation] for range in range_variation: pay_sheet_dict = {} #pay_sheet_dict['range']=range[range.rfind('/')+1:] pay_sheet_dict['id'] = pay_sheet_line.getId() pay_sheet_dict['title'] = pay_sheet_line.getResourceTitle() for cell in pay_sheet_line.objectValues(): predicate_list = cell.getMembershipCriterionCategoryList() if range in predicate_list: pay_sheet_dict['base_name'] = context.portal_categories.resolveCategory(range).getTitleOrId() for predicate in predicate_list: if cell.getTotalPrice() != 0: if predicate.find('employee_share')>=0: pay_sheet_dict['base']= - cell.getQuantity() pay_sheet_dict['employee_share'] = cell.getTotalPrice() pay_sheet_dict['employee_share_rate'] = cell.getPrice() * 100 total_employee_share += float(-pay_sheet_dict ['employee_share']) # here we decide if a resource is taxable or not if str(pay_sheet_line.getResource())[-14:] == 'non_deductible' or str(pay_sheet_line.getResource())[-4:] == 'crds' or str (pay_sheet_line.getResource())[-7:] == 'taxable': pay_sheet_dict['taxable']='yes' elif str(pay_sheet_line.getResource())[-10:] == 'deductible': pay_sheet_dict['taxable']='no' else: pay_sheet_dict['taxable']='no'
page 51/64
Tut o r i e l N e x e d i ERP5
if pay_sheet_dict['taxable'] == 'yes': total_taxable_employee_share += float(-pay_sheet_dict ['employee_share']) elif predicate.find('employer_share')>=0: pay_sheet_dict['base'] = - cell.getQuantity() pay_sheet_dict['employer_share'] = cell.getTotalPrice() pay_sheet_dict['employer_share_rate'] = cell.getPrice() * 100 total_employer_share += float(-pay_sheet_dict ['employer_share']) for key in ('employee_share','employee_share_rate','employer_share','employer_share_rat e'): if not (pay_sheet_dict.has_key(key)): pay_sheet_dict[key]='' # so that we can display nothing # find the category of the current pay sheet line cat_id = None cat_path = None for var in variation_list: sub_cat = var.split('/') if sub_cat[0] == 'tax_category': cat_id = sub_cat[1] cat_path = sub_cat[0] + '/' + sub_cat[1] break if cat_id == None: cat_id = 'no_cat' # add the current pay sheet line to its category if not paysheet_cat.has_key(cat_id): paysheet_cat[cat_id] = {} paysheet_cat[cat_id]['lines'] = [] if cat_path != None: paysheet_cat[cat_id]['title'] = context.portal_categories.resolveCategory(cat_path).getTitleOrId() paysheet_cat[cat_id]['lines'].append(pay_sheet_dict) # get all paysheet transaction to calculate the sum of different value in a year accounting_folder = context.aq_parent paysheet_transactions = accounting_folder.contentValues(filter= {'portal_type':'Pay Sheet Transactionss'}) # initialize every yearly variable yearly_net_salary = 0.0 yearly_gross_salary = 0.0 yearly_employee_share = 0.0 yearly_employer_share = 0.0 yearly_taxable_net_salary = 0.0 # get the current paysheet start date and employee start_date = context.getStartDate() from DateTime import DateTime start_date = DateTime("%i/01/01" % start_date.year()) stop_date = context.getStopDate() employee = context.restrictedTraverse (context.getDestinationSectionRelativeUrl())
page 52/64
Tut o r i e l N e x e d i ERP5
#start_date = start_date.strftime('%Y-%m-%d') #stop_date = start_date.strftime('%Y-%m-%d') #yearly_employee_share = -float (context.PaySheetTransaction_zGetDetailedTotal (start_date=start_date,stop_date=stop_date,tax_category='employee_share') [0].total) #yearly_employer_share = -float (context.PaySheetTransaction_zGetDetailedTotal (start_date=start_date,stop_date=stop_date,tax_category='employer_share') [0].total) yearly_employee_share = 0 yearly_employer_share = 0 try: yearly_employer_share = -float (context.PaySheetTransaction_zGetDetailedTotal (start_date=start_date,stop_date=stop_date,tax_category='employer_share') [0].total) except: pass # browse through paysheet transaction for paysheet_obj in paysheet_transactions: # ignore the current paysheet to avoid infinite loop if paysheet_obj.getId() != context.getId(): # the paysheet must have the same employee if (employee==None) or (employee!=None and context.restrictedTraverse (paysheet_obj.getDestinationSectionRelativeUrl())==employee): # check the date if (start_date==None) or (start_date!=None and paysheet_obj.getStartDate()!=None and start_date.year() ==paysheet_obj.getStartDate().year() and paysheet_obj.getStartDate()<= start_date): # get all detailed values of the paysheet ps_details = paysheet_obj.PaySheetTransaction_getDetails() # sum of yearly values yearly_net_salary += float(ps_details['net_salary']) yearly_gross_salary += float(ps_details['gross_salary']) yearly_employee_share += float(ps_details ['total_employee_share']) yearly_employer_share += float(ps_details ['total_employer_share']) yearly_taxable_net_salary += float(ps_details ['taxable_net_salary']) # save the total share values in the exported dict paysheet_details['net_salary'] = gross_salary total_employee_share paysheet_details['gross_salary'] = gross_salary paysheet_details['paysheet_categories'] = paysheet_cat paysheet_details['total_employee_share'] = total_employee_share paysheet_details['taxable_net_salary'] = paysheet_details ['net_salary'] + total_taxable_employee_share paysheet_details['total_employer_share'] = total_employer_share
page 53/64
Tut o r i e l N e x e d i ERP5
paysheet_details['total_taxable_employee_share'] total_taxable_employee_share # don't forget to add the current values to the paysheet_details['yearly_net_salary'] = paysheet_details['net_salary'] paysheet_details['yearly_gross_salary'] = paysheet_details['gross_salary'] paysheet_details['yearly_employee_share'] = paysheet_details['total_employee_share'] paysheet_details['yearly_employer_share'] = paysheet_details['total_employer_share'] paysheet_details['yearly_taxable_net_salary'] = paysheet_details['taxable_net_salary'] return paysheet_details
= yearly sum yearly_net_salary + yearly_gross_salary + yearly_employee_share + yearly_employer_share + yearly_taxable_net_salary +
Une première version de notre Page Template pourrait ressembler à ceci :
<?xml version="1.0" encoding="iso-8859-1" ?> <document filename="report01.pdf" xmlns:tal="http://xml.zope.org/namespaces/tal" tal:define="employee python: here.getDestinationSectionValue(); employer python: here.getSourceSectionValue(); paysheet_details python: here.PaySheetTransaction_getDetails(); paysheet_categories python: paysheet_details ['paysheet_categories']; urssaf python: employer.getDestinationSectionValue(); start_date python: here.getStartDate(); boldstyle python:'(\'FONT\', \'Helvetica-Bold\', 7)'"> <title>VPN</title> <author>Nexedi</author> <subject>VPN List</subject> <content> <table splitbyrow="1" rowheight='0.4cm' repeatrows="1" repeatcols="0" style="decompte"> <tr> <td colwidth="4.318cm">Nature</td> <td colwidth="3.81cm">Assiette</td> <td colwidth="1.524cm">Montant</td> <td colwidth="2.77cm">Taux part patronale</td> <td colwidth="2.288cm">Part patronale</td> <td colwidth="2.397cm">Taux part salariale</td> <td colwidth="1.959cm">Part salariale</td> </tr> <tr tal:attributes="stylecmd boldstyle"> <!--stylecmd="('FONT', 'Helvetica-Bold', 7)"> --> <td>Salaire brut</td>
page 54/64
Tut o r i e l N e x e d i ERP5
<td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td tal:content="python: '%.2f' % paysheet_details ['gross_salary']" tal:condition="python: paysheet_details['gross_salary'] not in (None, '')">???</td> </tr> <tal:block tal:condition="python: paysheet_categories.has_key ('no_cat')"> <tal:block define="no_cat_lines python: paysheet_categories ['no_cat']['lines']"> <tr tal:repeat="line no_cat_lines"> <td><tal:block content="python: line['title']"/> </td> <td content="python: line['base_name']"> </td> <td content="python: '%.2f' % line['base']" tal:condition="python: line['base'] not in (None, '')"> </td> <td content="python: '%.3f %%' % line['employer_share_rate']" tal:condition="python: line['employer_share_rate'] not in (None, '')"> </td> <td content="python: '%.2f' % line['employer_share']" tal:condition="python: line['employer_share'] not in (None, '')"> </td> <td content="python: '%.3f %%' % line['employee_share_rate']" tal:condition="python: line['employee_share_rate'] not in (None, '')"> </td> <td content="python: '%.2f' % line['employee_share']" tal:condition="python: line['employee_share'] not in (None, '')"> </td> </tr> </tal:block> </tal:block> <tal:block repeat="category paysheet_categories"> <tr tal:attributes="stylecmd boldstyle"> <td tal:content="python: paysheet_categories[category] ['title']"> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> <tal:block define="paysheet_lines python: paysheet_categories [category]['lines']"> <tr tal:repeat="line paysheet_lines" stylecmd="('LEFTPADDING',8)"> <td><tal:block tal:content="python: ' ' + line['title']"/> </td> <td><tal:block tal:content="python: line['base_name']"/> </td> <td> <tal:block content="python: '%.2f' % line['base']" tal:condition="python: line['base'] not in (None, '')"></tal:block></td> <td> <tal:block content="python: '%.3f %%' % line ['employer_share_rate']" tal:condition="python: line['employer_share_rate'] not in (None, '')"></tal:block></td>
page 55/64
Tut o r i e l N e x e d i ERP5
<td> <tal:block content="python: '%.2f' % line ['employer_share']" tal:condition="python: line['employer_share'] not in (None, '')"></tal:block></td> <td> <tal:block content="python: '%.3f %%' % line ['employee_share_rate']" tal:condition="python: line['employee_share_rate'] not in (None, '')"></tal:block></td> <td> <tal:block content="python: '%.2f' % line ['employee_share']" tal:condition="python: line['employee_share'] not in (None, '')"></tal:block></td> </tr> </tal:block> </tal:block> <tr tal:attributes="stylecmd boldstyle"> <td>Total des cotisations</td> <td> </td> <td> </td> <td> </td> <td> <tal:block replace="python: '-%.2f' % paysheet_details ['total_employer_share']" tal:condition="python: paysheet_details ['total_employer_share'] not in ('', None)"> </tal:block></td> <td> </td> <td> <tal:block replace="python: '-%.2f' % paysheet_details ['total_employee_share']" tal:condition="python: paysheet_details ['total_employee_share'] not in ('', None)"> </tal:block></td> </tr> <tr tal:attributes="stylecmd boldstyle"> <td>Salaire Net</td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> <tal:block replace="python: '%.2f' % paysheet_details ['net_salary']" tal:condition="python: paysheet_details['net_salary'] not in ('', None)"> </tal:block></td> </tr> <tal:block repeat="category paysheet_categories"> <tal:block define="paysheet_lines python: paysheet_categories [category]['lines']"> <tal:block repeat="line paysheet_lines"> <tr tal:condition="python: line.has_key('taxable') and line ['taxable']=='yes'"> <td> <tal:block content="python: line['title']"/></td> <td> <tal:block content="python: line['base_name']"/></td> <td> <tal:block replace="python: '%.2f' % line['base']" tal:condition="python: line['base'] not in ('', None)"></tal:block></td> <td> </td> <td> </td> <td> <tal:block replace="python: '%.3f %%' % line ['employee_share_rate']" tal:condition="python: line['employee_share_rate'] not in ('', None)"></tal:block></td>
page 56/64
Tut o r i e l N e x e d i ERP5
<td> <tal:block replace="python: '+%.2f' % abs(float(line ['employee_share']))" tal:condition="python: line['employee_share'] not in ('', None)"></tal:block></td> </tr> </tal:block> </tal:block> </tal:block> <tr tal:attributes="stylecmd boldstyle"> <td>Salaire Net Imposable</td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> <tal:block replace="python: '%.2f' % paysheet_details ['taxable_net_salary']" tal:condition="python: paysheet_details ['taxable_net_salary'] not in ('', None)"> </tal:block></td> </tr> </table> <table rowheight="0.6cm"><tr><td> </td></tr></table> <table style="cumul_conges"> <tr> <td colwidth="11cm"> <tal:block tal:replace="python: 'Cumuls annuels (%s)' % start_date.year()" tal:condition="python: start_date not in ('', None)"/></td> <td colwidth="3cm"> </td> <td colwidth="5cm"> <!-- <tal:block tal:replace="python: 'Durée des congés payés : ???'"/> --> </td> </tr> </table> <table style="cumul_conges_corps"> <tr> <td colwidth="2cm">Salaire brut</td> <td colwidth="3cm">Cotisations salariales</td> <td colwidth="2cm">Salaire net</td> <td colwidth="2cm">Net imposable</td> <td colwidth="2cm">Part patronale</td> <td colwidth="3cm"> </td> <td colwidth="5cm"> <tal:block tal:replace="python: 'Durée des délais de préavis : ' + context.PaySheetTransaction_getPreavis()"/></td> </tr> <tr> <td> <tal:block replace="python: '%.2f' % paysheet_details ['yearly_gross_salary']" tal:condition="python: paysheet_details ['yearly_gross_salary'] not in ('', None)"></tal:block></td> <td> <tal:block replace="python: '%.2f' % paysheet_details ['yearly_employee_share']" tal:condition="python: paysheet_details ['yearly_employee_share'] not in ('', None)"></tal:block></td> <td> <tal:block replace="python: '%.2f' % paysheet_details ['yearly_net_salary']" tal:condition="python: paysheet_details ['yearly_net_salary'] not in ('', None)"></tal:block></td>
page 57/64
Tut o r i e l N e x e d i ERP5
<td> <tal:block replace="python: '%.2f' % paysheet_details ['yearly_taxable_net_salary']" tal:condition="python: paysheet_details ['yearly_taxable_net_salary'] not in ('', None)"></tal:block></td> <td> <tal:block replace="python: '%.2f' % paysheet_details ['yearly_employer_share']" tal:condition="python: paysheet_details ['yearly_employer_share'] not in ('', None)"></tal:block></td> <td> </td> <td> </td> </tr> </table> </content> </document>
Ajoutons ensuite une action dans le portal type des Pay Sheet Transaction avec la valeur object_print pour category :
Grâce à cette petite manipulation il nous reste plus qu'à cliquer sur l'icône de l'imprimante dans la vue d'une feuille de paie pour récupérer la version imprimable :
La Page Template sera appelée dans le contexte actuel et la feuille de paie imprimable s'affichera à l'écran sous forme de document PDF :
page 58/64
Tut o r i e l N e x e d i ERP5
Illustration 8: Une feuille de paie générée par ERP5
La technologie employée pour le rendu PDF est reportlab. Il s'agit d'une bibliothèque écrite en python, utilisée par des établissements financiers prestigieux et capable de générer plusieurs centaines de pages PDF par minute sur un serveur bas de gamme.
page 59/64
Tut o r i e l N e x e d i ERP5
3.11. La création du business template
Maintenant que le module fonctionne dans son ensemble, nous allons le rassembler au sein d'un Business Template pour pouvoir le distribuer et l'installer facilement. La procédure de création d'un Business Template est assez rapide si on connaît exactement toutes les composantes qui sont nécessaire au bon fonctionnement du module que l'on veut packager. Il faut d'abord nous rendre dans l'outil portal_templates et ajouter un nouveau Business Template en utilisant le menu "Action". Nous appellerons ce Business Template erp5_payroll et allons maintenant l'éditer et lister dans les différents champs les objets qui doivent être inclus :
http://localhost:9080/erp5/portal_templates/GestionDesSalaires/view
Les champs renseignés sont :
· · · ·
id : L'id du Business Template Name : le nom du Business Template, qui doit être unique pour chaque groupe de fonctionnalités Portal Types : la liste des types documentaires définis par le Business Template Skin Folders : le dossier dans portal_skins où sont stockés les éléments de présentation
page 60/64
Tut o r i e l N e x e d i ERP5
· ·
Base Categories : les catégories et relations nécessaires au fonctionnement du module Paths : des documents nécessaires au fonctionnement du module (ici, les organisations URSSAF, etc, nécessaires au calcul de la paye)
Maintenant que le Businnes Template connaît toutes les composantes de notre module, nous pouvons construire le Business Template via l'action "Build Business Template" du menu "Action" puis à l'export via l'action "Export Busines Template" du même menu. On peut dès à présent tester notre nouveau Business Template sur une nouvelle instance de Zope pour s'assurer que notre module fonctionne avant de le distribuer.
page 61/64
Tut o r i e l N e x e d i ERP5
3.12. Le point sur la catalogage
Le catalogage est en fait un moyen de stocker certaines information d'un objet (comme sont ID, titre, description, etc) dans une base de donnée annexe. Le catalogue permet de sélectionner instantanément des objets sans reparcourir toute la base objet de Zope. Il permet d'effectuer des requêtes rapides sur des bases de grande taille. Nexedi a par exemple déployé un système contenant plus de 2.000.000 de documents et plus de 10 000 000 d'enregistrements de catalogue. La technologie de catalogue développée par Nexedi pour ERP5 se nomme "ZSQL Catalog". C'est un produit zope qui permet d'effectuer des requêtes SQL sans limite de complexité sur un catalogue dont la structure est elle-même adaptable sans limites. L'objectif est de constituer un catalogue selon un modèle d'indexation susceptible d'offrir des temps de réponse très courts. L'approche est similaire à celle utilisée par les moteurs OLAP ou le datawarehousing pour le traitement statistiques de données consolidées.
page 62/64
Tut o r i e l N e x e d i ERP5
4. Conclusion
Nous avons appris dans cet article à installer une plateforme ERP5 et ses modules grâce au système de Business Template d'ERP5. Nous avons ensuite créé une version simpliste du module de feuille de paie qui existe déjà dans ERP5. Il existe beaucoup de différences entre ces deux versions. En particulier, le module de paye d'ERP5 repose sur le moteur de planification d'ERP5 afin de permettre des prévisions de trésorerie. Cependant, la structure de donnée et les principes de base restent les mêmes. Nous pouvons désormais exploiter ERP5 pour construire en un temps record un ERP fonctionnel capable de gérer un grand nombre d'aspects d'une entreprise ou d'une organisation. La bibliothèque actuelle de Business Template, qui est appelée à croitre et à s'enrichir, offre à la fois des briques de base et une source d'inspiration. Si toutefois les Business Template existants ne répondent pas à votre besoin, vous disposez désormais des bases nécessaire pour créer les votres. Dans ce cas n'oubliez pas de partager avec nous vos créations sur le site web www.erp5.org et sur les mailing-list erp5-dev et erp5-user.
page 63/64
Tut o r i e l N e x e d i ERP5
5. TODO
Améliorations à envisager sur ce document. Question à se poser: * faut-il supprimer certaines parties trop détaillée ? (variantage, category, construction des classes) * indiquer les conventsion de nommage utilisées par ERP5 * créer avec le lecteur un nouveau folder dans les portal_skins et lui faire changer les settings pour lui expliquer comment erp5 va chercher les formulaire ? * dire à l'utilisateur qu'il est prudent de donner un nom à chaque formulaire * ne pas evoquer les paysheet transaction line ? (compression de l'article) TODO: * couper les parties des images qui ne sont pas utiles (surtout celle avec des scrennshot de dropdown list/combo) * mettre en italique les babarismes (getter / setter / packages / etc) ou trouver une version française * intégrer une bibliographie/webographie à la fin de l'article * intégrer "Lors du développement du véritable Business Template, que vous trouverez dans la section download du site erp5.org, nous n'avons pas eu besoin de créer de module. En réalité le produit final des feuilles de paie est rassemblé dans le Business Template Human Resources (HR) qui contient aussi les fonctionnalités de gestion de carrières et s'intègre dans différents modules pré-existants (les feuilles de paie dans le module Accounting et la gestion de carrières dans le module Person). " * simplifier les scripts et templates de rapports * mettre à jour les recopies d'écran qui mentionnent base_edit, base_update_relation, etc. en utilisant le nouveau nommage (Base_edit, Base_updateRelation, etc.)
page 64/64
Tut o r i e l N e x e d i ERP5
Développez votre propre Développez ERP grâce aux Business Templates ERP5
page 1/64
Tut o r i e l N e x e d i ERP5
page 2/64
Tut o r i e l N e x e d i ERP5
Sommaire
1. Introduction.............................................................................4 2. ERP5: un ERP pour tous............................................................5
2.1. ERP5 sans installation.......................................... .................................5 2.2. Installer un système ERP5....................................................................5 2.3. Etendre ERP5 avec les Business Templates........................................10
3. Créons notre propre Business Template !.................................16
3.1. Conception de la structure de données..............................................16 3.2. Le variantage par catégories..............................................................20 3.3. Intégrons notre structure de données dans ERP5...............................21 3.4. Web Développement rapide avec portal_classes................................22 3.5. Structure d'une classe Document dans ERP5......................................24 3.6. Créer un Module dans EPR5................................. ...............................27 3.7. Intégrer les classes, données, menus et présentation : l'outil portal_types............................................................ ...................................29 3.8. L'interface utilisateur avec ERP5Form........................................ .........30 3.9. Les scripts python de calcul....................................... .........................43 3.10. Le reporting..................................... .................................................50 3.11. La création du business template.....................................................60 3.12. Le point sur la catalogage................................................ .................62
4. Conclusion..............................................................................63 5. TODO.....................................................................................64
page 3/64
Tut o r i e l N e x e d i ERP5
1. Introduction
Cet article est destiné aux développeurs qui veulent s'approprier ERP5 et ses mécanismes pour en faire un outil de gestion d'entreprise qui répond exactement à leurs besoins. Avec ERP5, ce n'est plus l'entreprise qui se conforme à la logique ERP, c'est l'ERP qui s'adapte à la culture de l'entreprise, à ses méthodes et à ses habitudes de travail. ERP5 dispose sous forme de framework de tous les outils nécessaires pour atteindre cet objectif. Cela passe la plupart du temps par la réalisation ou la modification d'un module de l'ERP sous la forme d'un paquetage fonctionnel ou métier appelé "Business Template". Cet article vous apprendra à installer rapidement une plate-forme ERP5 grâce aux Business Template avant de vous accompagner dans la réalisation d'un module simple de gestion de feuilles de paie. Cette seconde partie de l'article sera l'occasion idéale d'aborder toutes les techniques de conception au sein d'ERP5 pour que vous puissiez par la suite créer vos propres Business Template de façon autonome.
Support Commercial ERP5 ERP5 est un ERP libre en licence GPL développé et édité par la société Nexedi. Nexedi coordonne un réseau de partenaires certifiés pour le déploiement de solutions ERP5 en entreprise. Nexedi et ses partenaires assurent à travers leurs équipes d'ingénieurs et leurs consultants l'assistance, la formation et le transfert des compétences nécessaires à la maîtrise d'ERP5 sur le terrain. http://www.erp5.org/sections/documentation/evangelism/enterprise/ Tel. +33 662 05 76 14 Mel. info@nexedi.com
page 4/64
Tut o r i e l N e x e d i ERP5
2. ERP5: un ERP pour tous
2.1. ERP5 sans installation
Si vous souhaitez utiliser ERP5 sérieusement et sans perdre du temps dans des problématiques d'installation sans valeur ajoutée, nous vous recommandons d'utiliser le LiveCD d'ERP5 (et d'y contribuer). Le LiveCD ERP5 a été conçu comme un outil de développement et de production, et pas seulement comme un démonstrateur. Il peut être téléchargé sur: http://livecd.erp5.org. Son principe est simple :
On inserre un CD dans un PC standard, on appuye sur démarrer puis, après quelques minutes, on installe des Business Template que l'on peut utiliser, paramétrer et étendre.
2.2. Installer un système ERP5
Si l'usage d'un LiveCD ne vous convient pas, il est cependant possible d'installer ERP5 de façon traditionnelle. Il faut compter entre quelques dizaines de minutes (si vous utilisez une distribution comme Mandrakelinux pour laquelle tous les paquetages et leurs dépendances ont été créés) et quelques jours (si vous utilisez une distribution sans paquetages ERP5).
page 5/64
Tut o r i e l N e x e d i ERP5
Pour fonctionner, ERP5 a besoin du serveur d'applications Zope sur lequel il se fonde et ainsi qu'un nombre conséquent de produits Zope. Nous avons aussi besoin d'installer MySQL-max (une version de la plus populaire des bases de données libres qui supporte les transactions). MySQL-max est utilisé par le moteur de recherche de Zope via le produit ZSQLcatalog. Pour un système complet, il nous faut donc :
·
un serveur Zope (et toutes ses dépendances lié à Python) comportant les optimisations développées par Nexedi en matière de méta-programmation1 les produits Zope BTreeFolder, Base18, CMF, CMFActivity, CMFCategory, CMFMailIn, CMFPhoto, CMFReportTool, ERP5, ERP5Catalog, ERP5Compatibility, ERP5Form, ERP5SyncML, ERP5Type, ExtFile, Formulator, Localizer, Photo, TranslationService, ZMailIn, ZMySQLDA et ZSQLCatalog.
MySQL-max
·
·
Pour mener à bien cette mission, il faudra compter sur les paquetages de votre distribution Linux. Vous pouvez aussi partir des sources et installer Zope par un traditionnel ./configure, make, make install. Quand aux produits Zope, ils sont très faciles et rapide à installer puisqu'il s'agit en fait d'archives à décompresser dans le répertoire Products de Zope (généralement /var/lib/zope/Products ou / usr/lib/zope/lib/python/Products) et de quelques extensions (zsqlbrain.py et InventoryBrain.py) à ajouter dans le répertoire Extensions de Zope (généralement /var/lib/zope/Extensions ou /usr/lib/zope/lib/python/Extensions). Vous trouverez sans trop de difficultés des didacticiels et de la documentation sur le net pour l'installation et la configuration globale de Zope. Les heureux utilisateurs de Mandrake peuvent se contenter d'un simple urpmi ERP5 mysql-max, après avoir ajouté les sources main, contrib et nexedi2 à leur gestionnaire de paquetages. Notons que l'ensemble des manipulations décrites dans cet article ont été réalisées sur une Mandrake 10.0 et devraient être équivalentes avec une Mandrake 10.1. Une fois l'installation le des paquetages terminée, utilisons la console d'administration de Zope, zopectl, pour changer le mot de passe par défaut de l'administrateur (le login par défaut étant admin). L'ajout d'un utilisateur ne peut se faire que si le serveur Zope est arrêté. Il se peut très bien que la procédure d'installation ait démarré le serveur, nous l' arrêterons donc avant la manipulation. Ensuite seulement nous pourrons démarrer MySQL-max et Zope :
[root@localhost /]# /etc/init.d/zope stop Arrêt de zope : . daemon process stopped
1 Le code source de ces optimisations est téléchargeable à l'URL http://www.nexedi.org/static/Mandrake/10.1/SRPMS/zope2.7.2rc1 1nxd.src.rpm 2 http://www.nexedi.org/static/Mandrake/10.1/RPMS ou http://www.nexedi.org/static/Mandrake/10.0/RPMS page 6/64
Tut o r i e l N e x e d i ERP5
[root@localhost /]# zopectl program: /usr/bin/runzope daemon manager not running zopectl> help adduser adduser -- add a Zope management user zopectl> adduser admin admin [root@localhost /]# /etc/init.d/mysql-max start Lancement du serveur MySQL [root@localhost /]# zopectl program: /usr/bin/runzope daemon manager not running zopectl> start daemon process started, pid=7944 [ OK ]
Il nous reste plus qu'à vérifier le fonctionnement de Zope en accédant à la ZMI, l'interface web de gestion de Zope, où l'on s'identifiera avec le mot de passe de l'utilisateur admin que l'on vient d'ajouter :
http://localhost:9080/manage
Illustration 1: L'accès à la Z MI nécessite une authentification
page 7/64
Tut o r i e l N e x e d i ERP5
Illustration 2: ZMI, l'interface web de gestion de Zope
Le serveur Zope étant désormais opérationnel et accessible, nous allons créer une instance d'ERP5 en sélectionnant le type ERP5 Site dans la liste déroulante en haut à droite :
Une page de propriétés est affichée dans la ZMI et nous la remplirons comme sur la capture d'écran :
page 8/64
Tut o r i e l N e x e d i ERP5
La validation de ce formulaire conduit à cet écran en cas de succès :
Mais il est fréquent de voir apparaître l'erreur suivante à ce moment précis :
Site Error An error was encountered while publishing this resource. Error Type: DatabaseError Error Value: z0_catalog_object is not connected to a database
Cette erreur signifie simplement que le serveur MySQL-max n'est pas démarré. Un redémarrage de ce dernier suffit pour que tout rentre dans l'ordre. On peut maintenant se rendre sur la page de garde d'ERP5 via l'url :
page 9/64
Tut o r i e l N e x e d i ERP5
http://localhost:9080/erp5/
ERP5 est maintenant opérationnel sur votre machine et se suffit à lui même pour commencer l'initiation. Je conseillerais cependant aux plus courageux de mettre à jour ERP5 depuis le CVS d'ERP53, pour pouvoir profiter des dernières évolutions et corrections de bugs. Mise en garde : bien que ERP5 soit maintenant installé et utilisable sur votre machine ou sur votre serveur, il n'est pas conseillé de l'utiliser "tel quel" en production. Une configuration fine (cluster, système d'activité, etc.) est en effet nécessaire pour obtenir des performances élevées et une réflexion sur la politique de sécurité des données est indispensable pour protéger des données vitales pour l'entreprise.
2.3. Etendre ERP5 avec les Business Templates
Les Business Templates sont à ERP5 ce que les systèmes de paquetages (rpm, apt) sont aux distributions Linux. Les RPM ont pour but de simplifier l'installation de logiciels au sein d'un système. Les Business Templates ont le même rôle en prenant en charge l'installation propre et automatisée de l'ensemble d'un module d'ERP5. D'un point de vue de l'utilisateur, installer un Business Template c'est ajouter une fonctionnalité majeure à l'ERP, en élargissant ses capacités de gestion d'entreprise. Il existe actuellement huit Business Templates, chacun étant dédié à un aspect de la gestion d'entreprise:
·
Trade : gestion commerciale (achats et ventes, commandes, bons de livraison, facturations, gestion des stocks) PDM (Product Data Management) : gestion des données produit (définition des produits, variantes, catégorisation, nomenclatures, gamme opératoire, catalogue multimédia) MRP (Manufacturing Ressources Planning) : organisation et gestion de production (ordres de fabrication, planning de production) CRM (Customer Relationship Management) : gestion des relations clientèles (base de données des organisation et des personnes, opportunités commerciales) Accounting : comptabilité (livre de comptes, rapports financiers)
·
·
·
·
3 http://cvs.erp5.org voir également le script update_cvs.sh dans /var/lib/zope/ qui permet d'automatiser les mises à jour page 10/64
Tut o r i e l N e x e d i ERP5
·
HR (Human Resources) : gestion des ressources humaines (livre de paie, gestion de carrières) eCommerce : commerce électronique (magasin de vente en ligne, affiliations) CMS (Content Management System) : gestion de contenu web (via NuxeoCPS4)
· ·
Certains de ces Business Template ont atteint un premier stade de maturité (ex. Accounting permet aujourd'hui de clôturer un exercice comptable). Les autres sont encore en cours d'intégration. En effet, bien que ERP5 soit utilisé aujourd'hui en production sur des sites importants avec une couverture fonctionnelle complète (ex. nomenclatures, gestion de production, calcul des besoins, gestion de stock, facturation, etc.), les clients d'ERP5 ne souhaitent pas pour la plupart financer le surcoût de l'intégration sous forme de Business Template générique du travail spécifique qui a été effectué pour adapter le framework ERP5 à leurs propres besoins. Le travail d'intégration des Business Template est donc effectué par Nexedi de façon bénévole. Voilà pourquoi toutes les fonctionnalités du framework ERP5 ne sont pas encore couvertes par les Business Template disponibles en téléchargement. L'un des premier module conçu qui utilise le système de Business Templates est le module de gestion de feuille de paie. Ce module permet de gérer un livre de paie et de créer des bulletins de salaire. C'est ce module qui nous servira de support tout au long de l'article. Nous allons maintenant détailler le processus d'installation de ce Business Template. Ce processus nécessite de disposer un compte avec les droits Manager. Tout convient d'accéder avec votre navigateur au module portal_templates en tapant une URL telle que http://localhost/erp5/portal_templates ou http://localhost:9480/erp5/portal_templates en fonction de votre configuration. Vous pourrez alors accéder à la liste des Business Template : d'abord, il
4 http://www.cpsproject.org/ page 11/64
Tut o r i e l N e x e d i ERP5
A titre de comparaison, un système ERP5 plus complet comporte de nombreux Business Templates :
Notre objectif est donc de passer d'une liste pratiquement vide de Business Template à une liste plus complète. Pour atteindre cet objectif, il suffit de cliquer sur le bouton "Import/Export" dans la deuxième barre de boutons à partir du haut de la page ERP5. Ce bouton ressemble à ceci :
Après avoir cliqué dessus, vous arrivez sur le dialogue d'import de Business Template :
page 12/64
Tut o r i e l N e x e d i ERP5
Utilisez alors le menu "Exchange Select" pour passer du dialogue "Import Business Template" à "Download Business Template" :
Il vous reste alors à saisir dans les deux champs, d'une part un identifiant du Business Template (ex. erp5_accounting) puis l'URL de ce Business Template (ex.
http://cvs.erp5.org/cgibin/viewcvs.cgi/*checkout*/erp5_bt5/erp5_trade.bt5?rev=HEAD&content-type=text/plain)
et à cliquer sur "Download Business Template". Le téléchargement sera effectué automatiquement (à condition d'avoir accès à Internet) et, en cas de succès, vous verrez apparaître un message "Business Template Downloaded Successfully". Vous pouvez alors cliquer sur le Business Template que vous venez de télécharger. Vous verrez alors un formulaire de définition :
page 13/64
Tut o r i e l N e x e d i ERP5
Pour procéder à l'installation, allez dans le menu "Action" et à appelez "Install Business Template"
Vous venez d'installer le Business Template de comptabilité d'ERP5. Ce module est indispensable pour le Business Template de paye. Continuons maintenant avec la paye. Le principe est le même, il faut juste importer un Business Template différent en lui donnant comme id erp5_payroll et comme URL de téléchargement http://cvs.erp5.org/cgibin/viewcvs.cgi/*checkout*/erp5_payroll/erp5_trade.bt5?rev=HEAD&contenttype=text/plain
Voici un exemple de feuille de paie généré par ce Business Template :
page 14/64
Tut o r i e l N e x e d i ERP5
Illustration 3: Une feuille de paie générée par ERP5
Pour créer cette feuille de paie, nous nous sommes basés sur un document disponible sur le site communautaire erp5.org (http://www.erp5.org/workspaces/project/erp5_payroll/erp5_pay_sheet_for_n). Ce document en anglais destiné aux débutants explique la procédure à suivre pour arriver à ses fins. Il vous aidera dans l'utilisation du module de feuille de paie. Maintenant que nous connaissons le principe des Business Template d'un point de vue utilisateur, nous pouvons entamer le coeur de cet article : la création d'un Business Template.
page 15/64
Tut o r i e l N e x e d i ERP5
3. Créons notre propre Business Template !
L'objectif de la seconde partie de cet article est d'offrir une vue d'ensemble de la plate-forme de développement ERP5 à des développeurs. Dans ce but nous allons reconstruire dans les grandes lignes le module de feuilles de paie. Cela nous donnera l'occasion de démontrer la convivialité et la puissance d'ERP5 pour la création rapide de modules fonctionnels, mais également d'approcher les technologies et les concepts qui sont à la base d'ERP5.
3.1. Conception de la structure de données
Les objets ERP5 dérivent tous de 5 classes fondamentales :
Ce modèle théorique d'EPR5 à déjà fait l'objet d'une publication scientifique5 qu'il sera intéressant de consulter pour comprendre les motivations qui se cachent derrière chacun des concepts clé d'ERP5. Nous retiendrons de ce document la description des 5 classes fondamentales :
·
Ressource
Le type Resource décrit une ressource abstraite d'un processus métier comme les compétences d'une personne, une devise, une matière première, ou un produit.
Node
·
Les objets de type Node peuvent envoyer ou recevoir des ressources. Un noeud peut représenter une entité physique (telle une machine de production, qui reçoit des matières premières, les transforment et les
5 http://www.computer.org/itpro/cover_stories/smets.htm page 16/64
Tut o r i e l N e x e d i ERP5
envoient) ou une entité abstraite (tel un compte en banque qui reçoit des sommes d'argents). Les stocks sont représentés par des noeuds. Des métanoeud (MetaNode) sont des noeuds qui contiennent d'autres noeuds. C'est le cas par exemple d'une entreprise.
·
Movement
Cette classe décrit le mouvement de ressources entre deux noeuds à un moment donné, pour un temps donné. Par exemple un mouvement peut décrire l'envoi de matière premières d'un stock vers un atelier; un mouvement peut aussi représenter l'envoi d'argent depuis un compte vers un autre.
Path
·
Un chemin décrit le moyen pour un noeud d'accéder à une ressource dont il a besoin. Des prix et des profils commerciaux peuvent être attachés à un chemin pour définir par exemple le prix par défaut d'une ressource fournit à un fabricant. Un chemin peut aussi définir la manière dont un atelier obtient ses ressources du stock. Un chemin possède des attributs de date de début et de fin, et peut représenter l'affectation d'un individu à une mission temporaire.
Item
·
Un item est une instance physique d'une quantité de ressource. Un mouvement peut se détailler en une série de mouvements traçable via des items. Les Items définissent aussi la manière dont les ressources sont livrées (selon un colis entier ou en listant les numéros de série des items dans chaque conteneur).
En analysant une feuille de paie française classique, nous avons choisis de créer 4 types d'objets :
· · · ·
PaySheetTransaction PaySheetTransactionLine PaySheetLine PaySheetCell
Voici un diagramme de classes qui donne la hiérarchie et les héritages permettant de relier les classes de bases d'ERP5 avec nos 4 nouveaux types d'objets :
page 17/64
Tut o r i e l N e x e d i ERP5
Folder
XMLObject
Movement
Delivery
DeliveryLine
DeliveryCell
Accounting Transaction
Invoice
Accounting Transaction Line
InvoiceLine
InvoiceCell
PaySheet Transaction
1
0..* Transaction
Line
PaySheet
0..*
PaySheet Line
1
0..*
PaySheet Cell
La structure de données des feuilles de paie est calquée sur le modèle de facturation (Invoice). Ce dernier est décrit par 3 classes : Invoice, InvoiceLine et InvoiceCell. Ces trois classes permettent de détailler une facture (Invoice) en lignes de facturation via InvoiceLine (une ligne de facture par produit facturé), elles mêmes décomposables selon des variantes du même produit facturé. Ainsi les InvoiceCell permettent par exemple de détailler la facturation d'une uantité de quatre produits A en trois produits A de couleur bleue et un produit A de couleur verte. Comme nous le montre le diagramme, les factures spécialisent le système de représentation des livraison (Delivery) qui implémente à l'origine la structure Line/Cell. Les cellules (Cell) sont la partie visible du concept de variantage qu'offre ERP5. Ce concept permet de représenter des variantes d'une même ressource comme la couleur, la taille ou la vitesse. Cela permet de définir plusieurs configurations d'un même produit. L'avantage de ce système réside dans la possibilité de configurer très profondément l'ERP5 tout en gardant les bénéfices d'une gestion générique des données selon une structure standardisée. Nous détaillerons le concept de variantage un peu plus loin dans cette article. Nous allons maintenant détailler nos différentes classes.
·
PaySheetTransaction
La feuille de paie en elle même est représentée par un objet de type
PaySheetTransaction.
page 18/64
Tut o r i e l N e x e d i ERP5
Cette classe dérive de la classe de base Folder via Invoice. Nous avons choisi cet héritage car les objets de type PaySheetTransaction vont nous servir à regrouper au même endroit les objets relatifs à une feuille de paie. C'est pour cela que PaySheetTransaction n'a pas comme classe ancêtre l'une des 5 classes de base d'ERP5. Folder est en quelque sorte une "classe utilitaire" qui nous permet de réduire l'entropie du système. Et comme les PaySheetTransaction sont des Folder avec des comportements particuliers dont certains sont les mêmes que pour une facture (Invoice), nous avons dû créer une nouvelle classe. Ces comportements particuliers permettront de prendre en compte la notion d'employeur et de salarié ainsi que d'autres données propres à la feuille de paie (date de paiement, salaire brut, ).
·
PaySheetLine
Comme l'indique le diagramme, chaque PaySheetTransaction peut contenir des PaySheetLine qui sont la représentation des différentes cotisations soustraite sur le salaire brut. Pour chaque cotisation il y a une et une seule PaySheetLine.
·
PaySheetCell
Les PaySheetLine contiennent les PaySheetCell, qui permettent de représenter et détailler les montants de la PaySheetLine. Le système de variantage permettra de distinguer les parts employeur et employée d'une cotisation sociale donnée et de conserver une trace de la méthode de calcul des montants. Car pour une cotisation donnée, le montant d'une part (salariale ou patronale) peut être le fruit d'un savant calcul faisant intervenir un ou plusieurs taux, associé chacun à une assiette (salaire brut, salaire plafonné, salaire tranche A/B/C, ). Le calcul des feuilles de paie n'est pas évident, d'autant plus que la législation change tout les jours Le variantage offre un avantage de taille dans ce cas car il permet de parer à toutes les complications induites par la législation de chaque pays.
·
PaySheetTransactionLine
Les PaySheetTransactionLine sont la représentation comptable de la feuille de paie. Nous avons choisi de distinguer les PaySheetLine et les PaySheetTransactionLine car la représentation de la feuille de paie selon la logique comptable agrège certains montants et rend impossible un reporting fin sur la paye. Nous avons donc au sein d'une PaySheetTransaction deux ensembles :
·
Les données du couple PaySheetLine/PaySheetCell : un jeu de données de
page 19/64
Tut o r i e l N e x e d i ERP5
base qui nous permet d'afficher les détails de la feuille de paie et de manipuler les chiffres dans tous les sens.
·
Les données de type PaySheetTransactionLine, qui représentent les lignes comptable de la feuille de paie
Maintenant que nous avons un modèle de données cohérent, nous allons l'implémenter dans ERP5.
3.2. Le variantage par catégories
Les objets de type Category sont utilisés dans ERP5 pour la classification. Par exemple, un document peut posséder un attribut couleur. Au lieu de laisser l'utilisateur entrer une valeur libre, via un champ texte, pour l'attribut couleur, on préférera attribuer à l'objet une catégorie. On fabriquera donc via la ZMI les catégories couleur/bleu, couleur/vert et couleur/rouge :
Les catégories peuvent contenir des sous-catégories. Par exemple pour décrire les régions géographiques :
region/europe region/europe/west/ region/europe/west/france region/europe/west/germany region/europe/south/spain region/americas region/americas/north region/americas/north/us
page 20/64
Tut o r i e l N e x e d i ERP5
region/americas/south region/asia
Dans cet exemple la catégorie de base est region. Les catégories ont d'autres avantages comme le catalogage automatique. Ce mécanisme rend possible l'utilisation de requêtes SQL pour sélectionner les objets de la ZODB selon la valeur de la catégorie (voir plus bas paragraphe : catalogage). Il est possible de créer des classifications "virtuelles" basée sur des documents existant ou sur des catégories. Par exemple, si un document est accessible à au chemin organisation/nexedi, et qu'il existe une catégorie de base client, l'outil portal_categories autorise la création de la catégorie virtuelle client/organisation/nexedi. Cela permet de représenter un lien relationnel selon le schéma : « le client de tel objet est l'organisation Nexedi ». Le concept de la virtualisation des catégories évite la duplication des informations en offrant des mécanismes équivalent à une base de donnée relationnelle.
3.3. Intégrons notre structure de données dans ERP5
Nous allons ajouter dans ERP5 toutes les classes d'objets que nous avons définies dans le paragraphe précédent. ERP5 possède des mécanismes propres pour définir de nouvelles classes d'objets, ce qui lui permet de prendre en charge la création dynamique et automatisée de méthodes. Le travail de création de nouvelles classes se limite donc à les décrire, ERP5 se chargera du reste, comme la création dynamique des "setter" et "getter". Les classes d'objets se définissent via un script python dans le dossier Document de l'instance Zope/ERP5. Nous allons créer une nouvelle classe PaySheetTransaction, et pour éviter de ressaisir tout le code, faire une copie du fichier Invoice.py que nous éditerons :
[root@localhost /]# cd /usr/lib/zope/lib/python/Products/ERP5/Document/ [root@localhost Document]# cp Invoice.py / var/lib/zope/Document/PaySheetTransaction.py [root@localhost Document]# vi /var/lib/zope/Document/PaySheetTransaction.py () [root@localhost Document]# chown zope:zope / var/lib/zope/Document/PaySheetTransaction.py [root@localhost Document]# chmod 755 / var/lib/zope/Document/PaySheetTransaction.py
Voici ce à quoi doit ressembler le fichier PaySheetTransaction.py après édition :
page 21/64
Tut o r i e l N e x e d i ERP5
from AccessControl import ClassSecurityInfo from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface from Products.ERP5.Document.Invoice import Invoice class PaySheetTransaction(Invoice): """ A paysheet will store data about the salary of an employee """ meta_type = 'ERP5 Pay Sheet Transaction' portal_type = 'Pay Sheet Transaction' add_permission = Permissions.AddPortalContent isPortalContent = 1 isRADContent = 1 # Declarative security security = ClassSecurityInfo() security.declareObjectProtected(Permissions.View) # Default Properties property_sheets = ( PropertySheet.Base , PropertySheet.SimpleItem , PropertySheet.CategoryCore , PropertySheet.Task , PropertySheet.Arrow , PropertySheet.Delivery , PropertySheet.Movement , PropertySheet.Amount , PropertySheet.XMLObject , PropertySheet.PaySheetTransaction ) # Declarative Interface __implements__ = ( )
3.4. Web Développement rapide avec portal_classes
Il est possible de réaliser l'ensemble des opérations de création de classes ou d'édition du code via l'interface Web d'ERP5 grâce à l'outil portal_classes :
page 22/64
Tut o r i e l N e x e d i ERP5
L'édition de code python d'une classe ERP5 permet également de recharger à chaud le seul code modifié, sans redémarrer Zope et de gagner en productivité.
L'outil portal_classes est très utile en phase de prototypage ou de développement rapide. Il facilite également l'apprentissage d'ERP5. Il est cependant déconseillé de l'activer sur un système en production car il comporte des risques élevés en matière de sécurité. Aussi est-il désactivé par défaut dans le LiveCD ERP5 ou dans les paquetages ERP5 pour Mandrakelinux. Pour l'activer, il est donc nécessaire de créer un fichier vide ALLOW_CLASS_TOOL dans le répertoir du produit ERP5Type.
page 23/64
Tut o r i e l N e x e d i ERP5
3.5. Structure d'une classe Document dans ERP5
Les fichiers de type Document ont généralement la même allure, et les valeurs propres à notre nouvelle classe se devinent facilement. Toujours dans le dossier de l'instance Zope/ERP5, PropertySheet sert à contenir des scripts python similaires à ceux que l'on trouve dans le dossier PropertySheet du produit ERP5. Ces scripts aux noms évocateurs permettent de définir des attributs de classes et, par extension, le schéma de données d'ERP5. Les classes y font souvent référence grâce à la liste property_sheets, comme on peut le voir dans le code python précédent. Ainsi pour que chaque feuille de paye puisse stocker le salaire brut ("gross salary" en anglais), nous avons fait référence à la property sheet PaySheetTransaction qui contiendra la définition de l'attribut gross_salary de type flottant. Il nous faut maintenant la créer :
[root@localhost [root@localhost [root@localhost () [root@localhost [root@localhost /]# cd /var/lib/zope/PropertySheet/ PropertySheet]# touch PaySheetTransaction.py PropertySheet]# vi PaySheetTransaction.py PropertySheet]# chown zope:zope PaySheetTransaction.py PropertySheet]# chmod 755 PaySheetTransaction.py
Voici le contenu de la property sheet PaySheetTransaction.py :
class PaySheetTransaction: """ Properties for PaySheet Transaction objects """ _properties = ( { 'id' , 'description' paysheet' , 'type' , 'mode' }, ) _categories = ( , , , ) : 'gross_salary' : 'This variable contain the gross salary of the : 'float' : 'w'
'source' 'destination' 'source_section' 'destination_section'
La syntaxe est assez intuitive car tous les attributs se déclarent par une liste de dictionnaires python dans la variable _properties. Il convient juste de faire attention aux listes immuables (tuple) à un élement en python et à ne pas oublier la virgule avant la parenthèse de fin.
page 24/64
Tut o r i e l N e x e d i ERP5
[kevin@localhost Products]$ python Python 2.3.3 (#2, Feb 17 2004, 11:45:40) [GCC 3.3.2 (Mandrake Linux 10.0 3.3.2-6mdk)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> (5) 5 >>> (5,) (5,) >>> (5,10) (5, 10) >>>
Ainsi (5) est interprété comme l'entier 5, et (5,) comme une liste immuable contenant un seul élément entier égal à 5. La liste _categories contient la liste des catégories virtuelles. Nous utiliserons celles-ci pour créer un lien entre la feuille de paie, l'employeur et le salarié. La relation source_section fera référence à l'employeur (qui est l'organisation ou l'entreprise qui émet la feuille de paie) et la relation destination_section fera référence au salarié (la personne à qui se destine la feuille de paie). Si plus tard nous avons besoin de définir des attributs plus complexes, nous nous inspirerons des PropertySheets pré-existante dans le produit ERP5. Cette méthode est valable pour tous les points abordé dans cet article : puisque le code source est ouvert, il ne faut pas se priver de réutiliser ou de s'inspirer de choses existantes pour construire petit à petit des choses nouvelles. C'est même un obligation pour contribuer au code d'ERP5 : deux propriétés similaires doivent, par principe, avoir le même nom dans ERP5. Maintenant que notre nouvelle classe est construite, il est nécessaire soit de recharger son code (avec portal_classes sur la classe de PropertySheet puis sur la classe de Document) soit de redémarrer le serveur Zope pour qu'il puisse les prendre en compte. Si tout ce passe bien le serveur sera disponible et vous pourrez accéder à la ZMI :
[root@localhost kevin]# zopectl program: /usr/bin/runzope program running; pid=4450 zopectl> restart . daemon process restarted, pid=4773 zopectl> logtail -----2004-05-12T18:50:03 INFO(0) Z2 Caught signal SIGTERM -----2004-05-12T18:50:03 INFO(0) Z2 Shutting down fast -----2004-05-12T18:50:03 INFO(0) ZServer closing HTTP to new connections -----2004-05-12T18:50:03 INFO(0) ZServer closing FTP to new connections -----page 25/64
Tut o r i e l N e x e d i ERP5
2004-05-12T18:50:03 INFO(0) Zope Shutting down with exit code 0 () -----2004-05-12T18:50:42 INFO(0) Zope Ready to handle requests zopectl>
Il est possible qu'au moment du redémarrage, Zope s'arrête et refuse obstinément de démarrer. Il est aussi possible d'observer un comportement étrange de Zope : l'arrêt et le démarrage en boucle du serveur par périodes de 10 secondes. Les causes de ce blocage sont liées dans la majorité des ca à de mauvaises permissions sur les scripts ou à une mauvaise attribution de la propriété des fichiers que vous venez de créer. Une série de chmod et chown réglera ce problème. Si malgré ces corrections le problème persiste, il zopectl intègre une commande debug, qui lorsqu'on l'appelle va arrêter le serveur et le démarrer en vous affichant le log de démarrage et un rapport d'exécution (traceback) en cas d'erreur. Par exemple :
[root@localhost kevin]# zopectl program: /usr/bin/runzope daemon manager not running zopectl> debug Starting debugger (the name "app" is bound to the top-level Zope object) () Traceback (most recent call last): File "", line 1, in ? File "/usr/lib/python2.3/site-packages/PIL/__init__.py", line 50, in app File "/usr/lib/python2.3/site-packages/PIL/__init__.py", line 46, in startup File "/usr/lib/zope/./build/build-base/python-2.3/buildlib/Zope/App/startup.py", line 45, in startup File "/usr/lib/zope/./build/build-base/python-2.3/buildlib/OFS/Application.py", line 631, in import_products File "/usr/lib/zope/./build/build-base/python-2.3/buildlib/OFS/Application.py", line 654, in import_product File "/usr/lib/zope/lib/python/Products/ERP5/__init__.py", line 50, in ? from Tool import Category, CategoryTool, SimulationTool, RuleTool, IdTool, TemplateTool, TestTool File "/usr/lib/zope/lib/python/Products/ERP5/Tool/Category.py", line 35, in ? from Products.ERP5.Document.MetaNode import MetaNode File "/usr/lib/zope/lib/python/Products/ERP5/Document/__init__.py", line 3145, in ? import PaySheetTransaction as ERP5PaySheetTransaction File "/usr/lib/zope/lib/python/Products/ERP5/Document/PaySheetTransaction.py", line 62
page 26/64
Tut o r i e l N e x e d i ERP5
__implements__ = ( ) ^ SyntaxError: invalid syntax >>>
Le traceback nous apprend qu'il y a une erreur invalid syntax dans le fichier / usr/lib/zope/lib/python/Products/ERP5/Document/PaySheetTransaction.py, ligne 62. En éditant le dit fichier on s'aperçoit en fait que le malheureux développeur a oublié de fermer la liste property_sheets avec une parenthèse. Il nous suffira dans ce cas que d'une petite correction pour pouvoir relancer le serveur zope Attention : pour utiliser la commande debug il ne faut pas oublier de mettre à on l'option debug-mode du fichier /etc/zope.conf. Il n'est d'ailleurs pas surprenant de devoir utiliser debug 30 fois par jour lorsque l'on débute et que l'on ne maîtrise pas la syntaxe de python, ou lorsque l'on travaille sur le CVS d'un projet ERP5 en équipe et que des conflits surgissent. Selon le même principe nous avons construit les nouveaux types
PaySheetTransactionLine, PaySheetLine et PaySheetCell. Par curiosité on pourra
aller consulter les classes pythons qui les définissent :
[root@localhost [root@localhost [root@localhost [root@localhost /]# cd /usr/lib/zope/lib/python/Products/ERP5/Document/ Document]# vi PaySheetTransactionLine.py Document]# vi PaySheetLine.py Document]# vi PaySheetCell.py
Le lecteur attentif aura sans doute remarqué ici que le code du module de paye est parfois situé dans le dossier /usr/lib/zope/lib/python/Products/ERP5/Document/ et parfois dans le dossier /var/lib/zope/Document. Une explication s'impose. Le dossier /var/lib/zope/Document est conçu pour le développement rapide de code d'extension au framework ERP5. C'est donc bien dans ce dossier qu'il faut commencer à travailler lorsque l'on conçoit un nouveau jeu de classes pour un client ou pour une future extension d'ERP5. Si ce jeu de classes semble suffisamment générique et susceptible de correspondre à une fonction universelle d'un ERP, il est conseillé de l'intégrer au projet ERP5 afin de le partager avec l'ensemble de la communauté. C'est bien le cas de la paye. En revanche, si ce jeu de classes est lié à un métier ou aux besoins spécifiques d'une entreprise, il n'y a aucune raison de l'intégrer au coeur d'ERP5. La paye faisant désormais partie du coeur d'ERP5, il nous arrivera souvent de mentionner des fichiers situés dans le dossier Document du produit ERP5. Cependant, pour les besoins du tutoriel, nous créerons tous les nouvelles classes dans les dossiers de l'instance Zope/ERP5, c'est-à-dire généralement /var/lib/zope.
3.6. Créer un Module dans EPR5
Lors de l'introduction de ce chapitre nous avons fait l'amalgame entre les
page 27/64
Tut o r i e l N e x e d i ERP5
Business Templates et les modules de l'ERP. Nous allons maintenant faire la différence et décrire plus précisément le rôle d'un module, au sens d'ERP5, puis en créer un. Un module est simplement un lieu dans l'interface utilisateur d'ERP5 ou se rassemblent les fonctionnalités propres à un aspect de la gestion d'entreprise. Le Business Template contient tous les scripts et objets qui permettent de faire fonctionner le module. D'où l'amalgame. La création rapide d'un nouveau module peut être effectuée en allant à l'URL :
http://localhost:9480/erp5/ERP5Site_viewCreateModuleDialog
où apparaît le dialogue suivant :
Ce dialogue comporte 6 paramètres :
· · · · · ·
Module Id : l'id du dossier (Folder) créé à la racine du site ERP5 et qui contiendra l'ensemble des feuilles de paye. Module Portal Type : le nom du type documentaire qui sera créé pour contenir toutes les feuilles de paye Module Title : le titre qui apparaîtra dans le menu modules pour le module de paye Object Portal Type : le nom du type documentaire qui sera créé pour définir les feuilles de paye Object Title : le titre qui apparaîtra par défaut pour chaque feuille de paye Portal Skins Folder : le dossier dans lequel seront créés les formulaires par défaut
En cliquant sur "Create Module", tous les types documentaires sont
page 28/64
Tut o r i e l N e x e d i ERP5
automatiquement créés et les menus mis à jour. Un module de paye "vide" vient d'être créé. Il s'agit désormais de le paramétrer.
3.7. Intégrer les classes, données, menus et présentation : l'outil portal_types
ERP5 est conçu autour de l'architecture Zope/CMF. L'une des caractéristiques du CMF est le concept d'outil (tool en anglais) placé à la racine d'un portail et conçu pour fournir divers services : traduction de formats de documents, gestion des menus associés à un document, internationalisation, synchronisation, etc. L'outil portal_types permet de créer des types génériques de document sur la base de nos classes définies dans la partie précédente et de leur associer des menus ainsi que des éléments de présentation. Nous ferons la distinction par la suite entre portal_types (l'outil) et les portal types (les types de document définis par l'outil portal_types). Le contenu de l'outil portal_types correspond aux modules et aux types documentaires disponibles dans l'instance ERP5.
Pour résumer on peut dire que tous nos portal types du genre PaySheet* sont des images dans Zope de nos classes définies par nos scripts python. La réalité est plus subtile car ils peut y avoir deux portal types différents qui se basent sur la même classe, car leur rôle premier est de créer des types
page 29/64
Tut o r i e l N e x e d i ERP5
documentaires. Par exemple depuis une même classe DocumentEcrit nous pouvons créer deux portal types différents : Article et CommuniquéDePresse. Les deux se décrivent par la même structure de données et les mêmes propriétés. L'intérêt de créer deux types de documents est que nous pouvons appliquer à chaque type un workflow différent ou une mise en page adaptée.
3.8. L'interface utilisateur avec ERP5Form
Nous allons exploiter ici les capacités de RAD (environnement de développement rapide) d'ERP5 via le produit ERP5Form, afin de définir l'interface utilisateur de notre module. ERP5Form est le générateur de formulaires d'ERP5. Il est dérivé de Formulator, un produit Zope créé par Infrae. Lorsque nous allons dans le module de paye, nous pouvons ajouter des PaySheetTransaction :
Cependant, notre action se termine sur une erreur :
page 30/64
Tut o r i e l N e x e d i ERP5
Or, la méthode de création d'une nouvelle feuille de paie à bien fonctionné comme l'atteste la présence dans la ZODB d'une nouvelle instance du portal type Pay Sheet Transaction qui à été créée dans le dossier paysheet du module :
Il ne s'agit donc que d'un problème de présentation. Pour le résoudre, nous devons ajouter une interface utilisateur à la feuille de paie pour que l'action de création n'aboutisse pas sur une erreur lorsque elle tente d'afficher l'objet créé. Nous allons donc créer un nouveau formulaire. Comme tous les formulaires et les autres objets de présentation, ils sont définis dans des sous-dossiers de l'outil portal_skins. Allons par exemple dans le dossier /erp5/portal_skins/local_erp5.
page 31/64
Tut o r i e l N e x e d i ERP5
Un formulaire se crée comme n'importe quel objet zope via la ZMI : il suffit de choisir le type "ERP5 Form". Appelons notre formulaire PaySheetTransaction_view :
Commençons pour l'éditer par lui ajouter un champ de type float pour représenter le salaire brut :
Pour indiquer implicitement que ce champ correspond à l'attribut gross_salary de notre objet, il suffit de le nommer my_gross_salary :
page 32/64
Tut o r i e l N e x e d i ERP5
L'utilisation du préfixe my_ est une des règles de nommage propre à ERP5. Si un champ de formulaire est nommé my_quelque_chose, il affichera par défaut une valeur obtenue en appelant la méthode getQuelqueChose sur le document auquel il est appliqué. En cas de validation du formulaire, la méthode setQuelqueChose sera appelée sur le document auquel le formulaire a été appliqué pour mettre à jour la valeur de la propriété quelque_chose. Pour être complet, il faut également configurer le formulaire pour que le salaire brut puisse être modifié en définissant la propriété Form action