Category Archives: OpenERP

Publication de mon mémoire de fin d’étude sur OpenERP

Bonjour à tous,

Cela fait quelques temps que j’avais promis de le faire mais sans jamais trouver le temps jusque là.

Je met aujourd’hui à disposition le mémoire de fin d’étude que j’ai présenté à mon école SUPINFO en octobre dernier. On peut dire que ce document est en quelque sorte le résumé et la conclusion de cette aventure entreprenariale qu’à pour moi représenté SYNERPGY.

J’y résume notamment pourquoi j’avais choisi à l’époque de me tourner vers OpenERP, les pièges à éviter quand on veut faire de l’intégration OpenERP (que j’ai souvent découvert à la dure) et enfin quelques recommandations pour l’avenir.

Ce document est sous licence Creative Common by-sa, c’est à dire que votre seule obligation est de ne pas changer la licence et de citer mon nom comme auteur du document. Pour le reste, vous pouvez vous en servir, le modifier etc… Au contraire, cela sera pour moi un plaisir que ce document soit repris dans d’autres circonstances.

Enfin, je précise que cela représentais mon opinion en septembre dernier. J’ai encore beaucoup évolué dans ma réflexion, notamment au niveau de la méthodologie qui est désormais beaucoup moins théorique (Je publierais la nouvelle version dès que j’en aurais l’occasion).
Merci donc de prendre simplement ce document comme une piste de réflexion et non comme forcément représentatif de mon opinion actuel (même si la grande majorité reste bien entendu d’actualité).

You can download it here : https://drive.google.com/file/d/0BwdMYBR15LiXejFxMnhLUHRSNUtDN0JCQ2M4N0hZUQ/view?usp=sharing

Enfin, j’en profite pour glisser un mot vu que la conclusion du mémoire porte dessus : Je prévois toujours de lancer, au moins en France, un site généraliste qui tenterai de centraliser les besoins en ERP de chaque secteur d’activité sur un site internet, pour ensuite comparer les ERPs du marché en fonction de ces besoins.
Comme je le marque en conclusion, le logiciel libre a besoin d’être précisément comparé aux alternatives propriétaires (de manière impartiale, précisons le) pour générer de la dynamique. Ce projet de site internet sera donc à la fois pour soutenir le libre et pour apporter un puissant outil de comparaisons aux utilisateurs.

Le projet est déjà défini, il ressemblera beaucoup au site openerp-universe.org que j’avais lancé l’année dernière. Il ne reste pour ainsi dire qu’à se mettre au travail, mais j’attend néanmoins si possible d’avoir la chance de convaincre quelques associations professionnelles d’adhérer au projet, leur soutien sera indispensable.

Si vous êtes intéressé par ce projet et souhaitez me donner un coup de main, n’hésitez pas à me contacter :), cela pourrait accélérer les choses.

———————————————————————-

Edit :
Après avoir reçu un petit mail de la part de Fabien, je pense qu’il convient de rétablir certaines vérités vis à vis de ma position à l’encontre de l’éditeur : Je suis désormais beaucoup moins à charge contre eux que je ne l’étais en septembre dernier, date de la rédaction du mémoire.

Même si mon avis sur l’éditeur ne représente qu’une petite partie du mémoire, je pense qu’il convient de leur rendre justice aussi je vous propose à la suite de ce billet le mail de réponse que j’ai envoyé à Fabien :

Bonjour Fabien, je te remercie d’avoir pris le temps de me faire parvenir tes remarques.

Avant toute chose, je précise que ma position vis-à-vis de l’éditeur a quand même pas mal évolué depuis septembre, date de la rédaction du mémoire, et dans l’ensemble effectivement on sent de l’amélioration. Mais j’avais promis de publier le mémoire, malheuresement sans avoir le temps de nuancer certaines parties pour refléter ma position actuelle. Je le précise d’ailleurs dans le billet : “Merci donc de prendre simplement ce document comme une piste de réflexion et non comme forcément représentatif de mon opinion actuelle”
Je ne te cache pas qu’en plus, le fait que la partie où j’analyse l’écosystème OpenERP étant situé à la fin du mémoire et avec la fatigue qui va avec, ceci ne m’a pas vraiment aidé à rester objectif.

Quelques remarques en vrac avant de commencer :

-Avoir le copyright sur le code noyau, tant que vous acceptez les merge proposal même avec copyright assignment, n’est pas sujet à critique selon moi. Ce qui le serait, et qui était ma crainte à l’époque, était que vous n’intégriez pas des modules complets et fonctionnels dans la branche addons simplement car vous n’en seriez pas l’auteur.

-Concernant la vitesse de traitement des bugs je suis désormais d’accord. Selon l’opinion générale, après des débuts parfois un peu difficile, il semble clair qu’aujourd’hui les processus au niveau du traitement des bugs sont désormais beaucoup plus efficaces.

-Sur la nécessité d’un organisme qui coordonne la communauté, où tu donne pour contre-exemple ce qui arrive actuellement à Drupal (que j’aime beaucoup d’ailleurs), je suis assez d’accord. Il semblerait qu’un tel organisme soit nécessaire, que ce soit un éditeur comme dans notre cas ou d’une fondation comme pour Linux ou Mozilla.

-Concernant l’exemple de PowerEmail que je donne dans mon mémoire, merci pour les explications. Je me garderai bien sûr de tout jugement, et me contenterai juste de noter avec satisfaction que le nom d’OpenLabs est bien présent sur l’actuel module email_template, ce qui remplit selon moi le contrat moral.
Après la seule question, c’est est-ce qu’il serait là s’il l’auteur n’avait pas tapé du poing sur la table à l’époque, mais cela je ne le saurais jamais et c’est aussi bien comme cela. L’essentiel c’est l’avenir.

-Je reconnais que par le passé, le temps de review des contributions était clairement plus dû à un manque de moyen que d’une politique de l’éditeur. Si je l’évoque dans mon mémoire, c’était plutôt dans l’objectif que cela ne devienne pas une politique de l’éditeur.

Concernant la prétendue volonté de l’éditeur de vouloir tout contrôler :

Lorsque j’ai écrit cette partie, j’avais en tête plusieurs choses :
-Le fait que sur quasiment tous les modules officiels à l’époque, seul le nom OpenERP était visible. Ceci donnait vraiment l’impression qu’OpenERP SA voulait que tout ce qui était certifié soit au nom d’OpenERP SA, et que les autres modules communautaires soient relégués dans les extra-addons.
Soyons clair, j’ai toujours eu confiance dans OpenERP SA (j’y reviens plus tard) mais quand je faisais cette analyse je me suis basé sur le pire scénario, que ce serait-il passé si la stratégie d’OpenERP SA était vraiment de vouloir à tout prix garder le contrôle sur la licence? Pas forcément en ayant de mauvaises intentions, mais même simplement pour pouvoir faire des ajustements à l’avenir. Et bien cela entrainerait forcément de mettre à l’écart certaines contributions de la communauté ce contre quoi je souhaitais lutter. C’est pour lutter contre ce potentiel scénario que j’ai présenté les choses sous cet angle.

-A cette période également, on avait eu quelques mois auparavant le changement de licence pour l’AGPL + exception (que je n’avais pas forcément mal accueilli comme tu le sais) mais qui avait aussi semble t’il provoqué de la réécriture d’une large partie du code juste pour contourner le copyright. Quelqu’en soient les raisons, même des très bonnes raisons et là je n’en sais rien, une réécriture de code unilatérale pour des raisons de licence aura toujours une mauvaise image.
J’avais également en tête les quelques scandales, justifiés ou non, comme PowerEmail, les commerciaux au Brésil, le départ du projet Medical etc… C’est pour tout cela, même si principalement par principe de précaution, que j’ai choisi à l’époque de partir sur le scénario “éditeur open-source, mais qui n’intègre pas toutes les contributions uniquement pour des raisons de licences”. J’avais tout simplement des craintes que j’estimais légitimes à l’époque.

Je précise également que je suis très loin d’être complètement à charge contre OpenERP SA dans mon mémoire. Je précise de nombreuses fois que vous êtes parmi les très rares dans les éditeurs de logiciels libres à destination des entreprises à ne pas être parti sur un modèle de double licence.
C’est très important pour moi, car tout spécialement dans le secteur des ERPs qui ne finira jamais de progresser, l’intégration des contributions de la communauté est capitale pour la compétitivité du logiciel à long terme. Cette dynamique serait complètement détruite en cas de double licence, et c’est pas pour rien que ceux qui ont tenté de faire un ERP en double licence sont aujourd’hui en difficulté.
Je pense que cela vous l’avez parfaitement compris. Je dirais même que vous avez fait preuve d’un véritable acharnement à éviter à tout prix ce modèle, testant modèle économique sur modèle économique (intégration pour démarrer, certification de module, SaaS, contrat de maintenance, partenariats etc etc…).

Je le dit sans arrière-pensée, vous êtes un vrai éditeur du libre, non un simple éditeur open-source. C’est pour cela que je soutiens toujours OpenERP.

Mais votre rôle est difficile, il est facile de faire des erreurs ou d’avoir à faire des mauvais choix pour le produit qui sont des bons choix pour la société. C’est pas forcément une mauvaise chose, vous devez survivre, mais il faut que des personnes dans la communauté soient vigilantes et jouent le rôle de contre-pouvoir si nécessaire car il faut des personnes qui soient là pour le produit (et les utilisateurs) et qui n’ont pas d’autres préoccupations.
J’espère faire parti de ces personnes, mais même si je suis intransigeant avec ce que j’estime être contre l’intérêt du produit (ex : les migrations, que j’estime contre l’intérêt du produit à long terme, mais qui vous a clairement permis de trouver un modèle économique stable à court terme) et que j’émets parfois des mises en garde, le fait que je sois sur OpenERP prouvera toujours que je soutiens OpenERP SA. Le jour où quelqu’un comme moi ne le fera plus, là vous pourrez commencer à vous inquiéter.

Cela étant dit et posé, maintenant que voyons-nous?

Dans la 6.1, sur les quelques 160 modules certifiés (j’entend par là, présents dans la branche “addons” et non “extra-addons”), une vingtaine sont des modules qui n’ont pas pour auteur OpenERP SA.
Dans les quelques échanges que j’ai eu avec d’autres partenaires, j’entend désormais beaucoup de “C’est mieux qu’avant quand même, les contributions sont intégrées plus facilement”.
Enfin moi-même, au moment où je travaillais sur la paye française (qu’il faut que je termine d’ailleurs…) j’ai bien senti que la dynamique propre à la contribution était bel et bien là, je n’avais aucun reproche à faire.

Je me permettrais juste une question : Les modules certifiés, donc présent dans la branche “addons” et dans l’installation de base d’OpenERP, peuvent être en simple AGPLv3 ou doivent être en AGPLv3+exception? Le cas échéant, cela signifierais que vous rejeteriez les contributions qui ne sont pas conforme à votre licence, ce qui ferai revenir en quelques sortes mes craintes.

En dehors de cela, il est désormais évident que mes craintes de l’époque ne sont plus justifiées, en tout cas pour le moment. Aujourd’hui, vous montrez bel et bien que pour vous l’intérêt du produit passe avant la licence.

J’avais tort de m’inquiéter à l’époque, et ce n’est là qu’une raison de me réjouir .

Je vais mettre de bon cœur ce message (sans citer ton mail) à la suite du billet de sorte à contrebalancer le contenu du mémoire sur les points évoqués.
L’analyse de l’écosystème d’OpenERP n’était qu’une partie du mémoire, je pense que ce message permettra de corriger ce qui n’est aujourd’hui plus d’actualité. Merci de m’avoir donné cette chance en pointant les points sujets à critique.

Pour le reste, je pense que ce ne sera pas la dernière fois que tu liras des critiques sur OpenERP SA sur mon blog, de même que ce ne sera pas la dernière fois que tu pourras retweet un billet en faisant l’éloge . Toujours dans un seul objectif : Qu’un jour, un ERP libre soit leader sur le marché, avec toutes les conséquences que cela entrainera sur le tissu économique en lui-même.

Bien cordialement,
Yannick.

Un manque de sérieux dans l’évolution du framework depuis quelque temps ?

Bonjour à tous,

Cela fait un moment que je n’avais pas posté de billet. Depuis l’été dernier la période a été très chargée pour moi du fait de la fin de mes études et de divers travaux sur lesquels j’aurais j’espère l’occasion de revenir plus tard.

Comme certains d’entre vous me l’ont déjà entendu dire, je me réclame d’être un « consultant fonctionnel », c’est-à-dire :

-Capable de comprendre et recueillir les besoins de l’entreprise utilisatrice
-Fort de cette compréhension et de celle des principaux modules d’OpenERP, je suis censé trouver la manière la plus pérenne pour développer une fonctionnalité et la modéliser avant d’envoyer en développement.
-Je suis capable de faire des développements basiques, comme rajouter un nouveau champ, adapter une vue, un droit d’accès, corriger une traduction…. Bref tout ce qui est pris en charge par le framework car celui-ci est censé gérer les besoins les plus courants de l’ERPs. Cela permet de soumettre l’interface au client dès le début du projet ce qui est un atout extrêmement efficace pour gagner du temps sur le projet.
-Je ne suis pas capable de faire du pur développement python. Je suis néanmoins capable de le lire et de faire parfois quelques corrections mineures.

Pourquoi je présente cette définition du consultant fonctionnel ? Car je pense que n’importe qui, qui a une expertise métier, peut devenir un consultant fonctionnel sur OpenERP, cela prendra juste du temps et au final vous ne serez bloqué que par les développements pointus.

C’est possible car depuis le départ, OpenERP a mis en place le framework OpenObject qui gère les objets en base de donnée, les menus, les vues, les droits d’accès, etc… Rendant pratiquement possible au premier venu de faire des modifications majeures sur le fonctionnement de l’ERP. Cela a toujours été la principale force d’OpenERP ! Sa simplicité d’accès au code des fonctionnalités

Ok Yannick, on sait déjà tout ça, où veux-tu en venir ?

Je veux en venir que j’ai l’impression que depuis la délocalisation des équipes de développements en Inde cet esprit s’est fortement perdu.

Je vais vous montrer un exemple qui m’avait littéralement assommé le jour où j’ai vu ça, sans trouver le temps avant aujourd’hui d’en parler.
Voici le code pour l’analyse statistique des factures :

def init(self, cr):
        tools.drop_view_if_exists(cr, 'account_invoice_report')
        cr.execute("""
            create or replace view account_invoice_report as (
                 select min(ail.id) as id,
                    ai.date_invoice as date,
                    to_char(ai.date_invoice, 'YYYY') as year,
                    to_char(ai.date_invoice, 'MM') as month,
                    to_char(ai.date_invoice, 'YYYY-MM-DD') as day,
                    ail.product_id,
                    ai.partner_id as partner_id,
                    ai.payment_term as payment_term,
                    ai.period_id as period_id,
                    (case when u.uom_type not in ('reference') then
                        (select name from product_uom where uom_type='reference' and active and category_id=u.category_id LIMIT 1)
                    else
                        u.name
                    end) as uom_name,
                    ai.currency_id as currency_id,
                    ai.journal_id as journal_id,
                    ai.fiscal_position as fiscal_position,
                    ai.user_id as user_id,
                    ai.company_id as company_id,
                    count(ail.*) as nbr,
                    ai.type as type,
                    ai.state,
                    pt.categ_id,
                    ai.date_due as date_due,
                    ai.address_contact_id as address_contact_id,
                    ai.address_invoice_id as address_invoice_id,
                    ai.account_id as account_id,
                    ai.partner_bank_id as partner_bank_id,
                    sum(case when ai.type in ('out_refund','in_invoice') then
                         ail.quantity / u.factor * -1
                        else
                         ail.quantity / u.factor
                        end) as product_qty,
                    sum(case when ai.type in ('out_refund','in_invoice') then
                         ail.quantity*ail.price_unit * -1
                        else
                         ail.quantity*ail.price_unit
                        end) / cr.rate as price_total,
                    sum(case when ai.type in ('out_refund','in_invoice') then
                         ai.amount_total * -1
                        else
                         ai.amount_total
                         end) / (CASE WHEN
                              (select count(l.id) from account_invoice_line as l
                               left join account_invoice as a ON (a.id=l.invoice_id)
                               where a.id=ai.id) <> 0
                            THEN
                              (select count(l.id) from account_invoice_line as l
                               left join account_invoice as a ON (a.id=l.invoice_id)
                               where a.id=ai.id)
                            ELSE 1
                            END) / cr.rate as price_total_tax,
                    (case when ai.type in ('out_refund','in_invoice') then
                      sum(ail.quantity*ail.price_unit*-1)
                    else
                      sum(ail.quantity*ail.price_unit)
                    end) / (CASE WHEN
                         (case when ai.type in ('out_refund','in_invoice')
                          then sum(ail.quantity/u.factor*-1)
                          else sum(ail.quantity/u.factor) end) <> 0
                       THEN
                         (case when ai.type in ('out_refund','in_invoice')
                          then sum(ail.quantity/u.factor*-1)
                          else sum(ail.quantity/u.factor) end)
                       ELSE 1
                       END)
                     / cr.rate as price_average,

                    cr.rate as currency_rate,
                    sum((select extract(epoch from avg(date_trunc('day',aml.date_created)-date_trunc('day',l.create_date)))/(24*60*60)::decimal(16,2)
                        from account_move_line as aml
                        left join account_invoice as a ON (a.move_id=aml.move_id)
                        left join account_invoice_line as l ON (a.id=l.invoice_id)
                        where a.id=ai.id)) as delay_to_pay,
                    sum((select extract(epoch from avg(date_trunc('day',a.date_due)-date_trunc('day',a.date_invoice)))/(24*60*60)::decimal(16,2)
                        from account_move_line as aml
                        left join account_invoice as a ON (a.move_id=aml.move_id)
                        left join account_invoice_line as l ON (a.id=l.invoice_id)
                        where a.id=ai.id)) as due_delay,
                    (case when ai.type in ('out_refund','in_invoice') then
                      ai.residual * -1
                    else
                      ai.residual
                    end)/ (CASE WHEN
                        (select count(l.id) from account_invoice_line as l
                         left join account_invoice as a ON (a.id=l.invoice_id)
                         where a.id=ai.id) <> 0
                       THEN
                        (select count(l.id) from account_invoice_line as l
                         left join account_invoice as a ON (a.id=l.invoice_id)
                         where a.id=ai.id)
                       ELSE 1
                       END) / cr.rate as residual
                from account_invoice_line as ail
                left join account_invoice as ai ON (ai.id=ail.invoice_id)
                left join product_template pt on (pt.id=ail.product_id)
                left join product_uom u on (u.id=ail.uos_id),
                res_currency_rate cr
                where cr.id in (select id from res_currency_rate cr2  where (cr2.currency_id = ai.currency_id)
                and ((ai.date_invoice is not null and cr.name <= ai.date_invoice) or (ai.date_invoice is null and cr.name <= NOW())) limit 1)
                group by ail.product_id,
                    ai.date_invoice,
                    ai.id,
                    cr.rate,
                    to_char(ai.date_invoice, 'YYYY'),
                    to_char(ai.date_invoice, 'MM'),
                    to_char(ai.date_invoice, 'YYYY-MM-DD'),
                    ai.partner_id,
                    ai.payment_term,
                    ai.period_id,
                    u.name,
                    ai.currency_id,
                    ai.journal_id,
                    ai.fiscal_position,
                    ai.user_id,
                    ai.company_id,
                    ai.type,
                    ai.state,
                    pt.categ_id,
                    ai.date_due,
                    ai.address_contact_id,
                    ai.address_invoice_id,
                    ai.account_id,
                    ai.partner_bank_id,
                    ai.residual,
                    ai.amount_total,
                    u.uom_type,
                    u.category_id
            )
        """)

134 lignes d’une pure requête SQL, juste pour créer une analyse statistique…
Alors ok c’est peut-être nécessaire, mais c’est dans le framework qu’on devrait retrouver ce code, pas dans l’un des modules fonctionnels ! Là on devrait juste lui dire voilà le nom de l’objet, voilà les champs à analyser et débrouille toi. Je ne reconnais pas du tout le code habituellement ultra-simple d’OpenERP dans ces 134 lignes, juste du code fait sans aucune réflexion préalable.

Quelle conséquence ? Moi, simple consultant fonctionnel, que ce passe-t il si je veux simplement rajouter un champ supplémentaire à analyser ? Ou créer une nouvelle analyse statistique sur un autre objet ? Ben je peux pas, obligé d’envoyer au développeurs qui vont me réécrire les 134lignes (ce qui pose un problème encore pire, j’y reviens).

Depuis quelques années, on constate qu’il n’y a plus de gros efforts au niveau du framework. Alors ok je soutiens à 300% le client web, la paye et encore plus le POS. Mais je commence à entrevoir de gros problèmes à l’avenir pour OpenERP qui risque de s’effondrer sur ses fondations, c’est-à-dire le framework.

Soyons clair, je ne suis pas en train de dire que OpenERP est mal codé, qu’il est pas « pythonic » ou autre. Je n’ai pas les compétences en développement pour ça et d’autres s’en chargent (dédicace aux gens de Tryton qui j’en suis sûr doivent se régaler avec ce billet…).
Ce que je veux dire c’est que les fonctionnels devraient pouvoir modifier encore beaucoup plus de fonctionnalités sur OpenERP que maintenant.

Ce qui se passe quand on passe une commande d’un statut à un autre, comme envoyer un mail, rajouter un module possible dans un wizard de configuration, ou encore transférer la valeur du champ qu’on vient de créer dans sale.order à son account.invoice etc…
Il y a encore plein de choses que nous pouvons faire, faire gérer  par OpenObject  encore plus de fonctions récurrentes dans les ERPs jusqu’à finir par limiter la part de code Python au strict minimum.

Qui plus est, cela sera je pense un bon moyen de limiter la quantité de code qui est pondu chaque jour par les équipes indiennes. Je suis désolé de dire ça mais à pas mal d’endroits j’ai parfois l’impression, pardonnez-moi l’expression, qu’ils ont juste « pissé du code » comme si ils étaient payé à la ligne. Je crains fortement que cela ne fasse courir un risque et qu’à terme on n’arrive plus à maintenir le logiciel.
Cadrer les équipes de développeurs dans OpenObject pour les développements les plus courants fera qu’ils n’auront qu’une manière de développer la fonctionnalité et qui sera la manière la plus simple. Cela permettra par la suite de pouvoir bien plus facilement maintenir le logiciel ou surtout refondre en profondeur un module (et cela arrivera pour certains, on peut en être sûr, on sera de plus en plus exigeant avec OpenERP au fur et à mesure que sa popularité grandit).

Et le pire c’est que pour certaines fonctionnalités elles sont déjà gérées par OpenObject. Par exemple la création d’une nouvelle facture avec les valeurs d’un bon de commande via ir.actions.server; mais comme dans les modules certifiés on ne l’utilise pas, personne n’utilise ces fonctionnalités…

Bref, je vais être clair sur ce que je propose : Dans un premier temps, il faut réécrire tous les modules certifiés pour qu’ils utilisent ir.actions.server ou utiliser un système équivalent. Ensuite continuer à améliorer le framework jusqu’à ce que le code Python dans les modules soit réduit au strict minimum.

Je suis certain que la majorité des lecteurs vont s’insurger contre cette idée, trop de travail, il vaut mieux laisser certaines fonctions en python pour avoir plus de flexibilité etc…  Pas de soucis, j’essaie juste de lancer le débat et j’espère juste qu’il va aboutir à des conclusions intéressantes.

J’aimerais néanmoins pointer du doigt un dernier problème, le pire je pense, et qui peut justement être résolu par une extension des possibilités d’OpenObject.

Prenons un partenaire A, très connu et top contributeur. Il a développé un module qui est très utilisé par d’autres membres de la communauté.

Dans son module, il a créé un champ X dans sale.order et dans account.invoice, et il a fait en sorte que sa valeur dans sale.order soit transmise à son account.invoice.

Voici le code qu’il a dû faire :

    def _make_invoice(self, cr, uid, order, lines, context=None):
        journal_obj = self.pool.get('account.journal')
        inv_obj = self.pool.get('account.invoice')
        obj_invoice_line = self.pool.get('account.invoice.line')
        if context is None:
            context = {}

        journal_ids = journal_obj.search(cr, uid, [('type', '=', 'sale'), ('company_id', '=', order.company_id.id)], limit=1)
        if not journal_ids:
            raise osv.except_osv(_('Error !'),
                _('There is no sales journal defined for this company: "%s" (id:%d)') % (order.company_id.name, order.company_id.id))
        a = order.partner_id.property_account_receivable.id
        pay_term = order.payment_term and order.payment_term.id or False
        invoiced_sale_line_ids = self.pool.get('sale.order.line').search(cr, uid, [('order_id', '=', order.id), ('invoiced', '=', True)], context=context)
        from_line_invoice_ids = []
        for invoiced_sale_line_id in self.pool.get('sale.order.line').browse(cr, uid, invoiced_sale_line_ids, context=context):
            for invoice_line_id in invoiced_sale_line_id.invoice_lines:
                if invoice_line_id.invoice_id.id not in from_line_invoice_ids:
                    from_line_invoice_ids.append(invoice_line_id.invoice_id.id)
        for preinv in order.invoice_ids:
            if preinv.state not in ('cancel',) and preinv.id not in from_line_invoice_ids:
                for preline in preinv.invoice_line:
                    inv_line_id = obj_invoice_line.copy(cr, uid, preline.id, {'invoice_id': False, 'price_unit': -preline.price_unit})
                    lines.append(inv_line_id)
        inv = {
            'name': order.client_order_ref or '',
            'origin': order.name,
            'type': 'out_invoice',
            'reference': order.client_order_ref or order.name,
            'account_id': a,
            'partner_id': order.partner_id.id,
            'journal_id': journal_ids[0],
            'address_invoice_id': order.partner_invoice_id.id,
            'address_contact_id': order.partner_order_id.id,
            'invoice_line': [(6, 0, lines)],
            'currency_id': order.pricelist_id.currency_id.id,
            'comment': order.note,
            'payment_term': pay_term,
            'fiscal_position': order.fiscal_position.id or order.partner_id.property_account_position.id,
            'date_invoice': context.get('date_invoice',False),
            'company_id': order.company_id.id,
            'user_id': order.user_id and order.user_id.id or False,
            'champ_x': order.champ_x
        }
        inv.update(self._inv_get(cr, uid, order))
        inv_id = inv_obj.create(cr, uid, inv, context=context)
        data = inv_obj.onchange_payment_term_date_invoice(cr, uid, [inv_id], pay_term, time.strftime('%Y-%m-%d'))
        if data.get('value', False):
            inv_obj.write(cr, uid, [inv_id], data['value'], context=context)
        inv_obj.button_compute(cr, uid, [inv_id])
        return inv_id

50 lignes, alors qu’en fait la seule ligne qu’il a vraiment codé c’est la ligne en rouge ici. Et encore on a eu de la chance, la fonction d’origine aurait pu être bien plus longue.
Comme il n’est pas possible via son module d’insérer son code directement, il a dû copier-coller l’ensemble de la fonction du module sale pour rajouter sa petite ligne.

Et là le vrai problème arrive. Pas de chance les devs de l’éditeur modifient par la suite la fonction d’origine et d’autres fonctions ailleurs, de sorte que l’ancienne provoque désormais un bug. Notre partenaire A doit désormais refaire le copier-coller de la fonction d’origine s’il ne veut pas que son module soit considéré comme buggé.

Cela oblige notre partenaire à faire de la veille permanente sur tous ses modules, juste pour vérifier qu’OpenERP SA n’a pas modifié la fonction d’origine. Et vu que les fonctions sont de plus en plus longues, les risques de bugs le sont d’autant plus. Enfin, cas ultime, imaginez si un partenaire B créé un module qui hérite de la fonction du module de A… Ce que je veux dire par là, c’est que c’est tout l’écosystème des modules communautaire qui est instable à cause de cette surutilisation des fonctions Python qui ne sont pas DU TOUT adaptées à un système aussi modulaire qu’OpenERP.

Je pense qu’on est en plein dedans aujourd’hui, on constate que de plus en plus de modules de qualité arrivent sur OpenERP, mais ils sont rapidement buggés dès que OpenERP SA fait des changements dans les fonctions des modules certifiés, qui deviennent eux-mêmes de plus en plus long et complexe.

Il faut à tout prix trouver une autre solution pour les développeurs de module pour ne pas avoir à recopier la fonction d’origine quand ils veulent juste rajouter quelques détails en plus comme un champ à transférer. Et pour moi la seule solution viable, comme il est clair qu’on ne pourra pas faire ça directement dans le code Python, c’est donc de diminuer la part de ce code Python en étendant et surtout utilisant les possibilités d’OpenObject qui peuvent je pense être encore améliorés.

Merci d’avoir tenu cette lecture. J’exprime ici ma conviction personnelle, qui est un peu isolée. Je ne suis pas développeur, aussi si j’ai peut-être dit de grosses conneries, n’hésitez pas à me l’indiquer dans les commentaires.

    def init(self, cr):
79
        tools.drop_view_if_exists(cr, 'account_invoice_report')
80
        cr.execute("""
81
            create or replace view account_invoice_report as (
82
                 select min(ail.id) as id,
83
                    ai.date_invoice as date,
84
                    to_char(ai.date_invoice, 'YYYY') as year,
85
                    to_char(ai.date_invoice, 'MM') as month,
86
                    to_char(ai.date_invoice, 'YYYY-MM-DD') as day,
87
                    ail.product_id,
88
                    ai.partner_id as partner_id,
89
                    ai.payment_term as payment_term,
90
                    ai.period_id as period_id,
91
                    (case when u.uom_type not in ('reference') then
92
                        (select name from product_uom where uom_type='reference' and active and category_id=u.category_id LIMIT 1)
93
                    else
94
                        u.name
95
                    end) as uom_name,
96
                    ai.currency_id as currency_id,
97
                    ai.journal_id as journal_id,
98
                    ai.fiscal_position as fiscal_position,
99
                    ai.user_id as user_id,
100
                    ai.company_id as company_id,
101
                    count(ail.*) as nbr,
102
                    ai.type as type,
103
                    ai.state,
104
                    pt.categ_id,
105
                    ai.date_due as date_due,
106
                    ai.address_contact_id as address_contact_id,
107
                    ai.address_invoice_id as address_invoice_id,
108
                    ai.account_id as account_id,
109
                    ail.account_id as account_line_id,
110
                    ai.partner_bank_id as partner_bank_id,
111
                    sum(case when ai.type in ('out_refund','in_invoice') then
112
                         -ail.quantity / u.factor
113
                        else
114
                         ail.quantity / u.factor
115
                        end) as product_qty,
116
117
                    sum(case when ai.type in ('out_refund','in_invoice') then
118
                         -ail.price_subtotal
119
                        else
120
                          ail.price_subtotal
121
                        end) / cr.rate as price_total,
122
123
                    (case when ai.type in ('out_refund','in_invoice') then
124
                      sum(-ail.price_subtotal)
125
                    else
126
                      sum(ail.price_subtotal)
127
                    end) / (CASE WHEN sum(ail.quantity/u.factor) <> 0
128
                       THEN
129
                         (case when ai.type in ('out_refund','in_invoice')
130
                          then sum(-ail.quantity/u.factor)
131
                          else sum(ail.quantity/u.factor) end)
132
                       ELSE 1
133
                       END)
134
                     / cr.rate as price_average,
135
136
                    cr.rate as currency_rate,
137
                    sum((select extract(epoch from avg(date_trunc('day',aml.date_created)-date_trunc('day',l.create_date)))/(24*60*60)::decimal(16,2)
138
                        from account_move_line as aml
139
                        left join account_invoice as a ON (a.move_id=aml.move_id)
140
                        left join account_invoice_line as l ON (a.id=l.invoice_id)
141
                        where a.id=ai.id)) as delay_to_pay,
142
                    sum((select extract(epoch from avg(date_trunc('day',a.date_due)-date_trunc('day',a.date_invoice)))/(24*60*60)::decimal(16,2)
143
                        from account_move_line as aml
144
                        left join account_invoice as a ON (a.move_id=aml.move_id)
145
                        left join account_invoice_line as l ON (a.id=l.invoice_id)
146
                        where a.id=ai.id)) as due_delay,
147
                    (case when ai.type in ('out_refund','in_invoice') then
148
                      -ai.residual
149
                    else
150
                      ai.residual
151
                    end)/ (CASE WHEN
152
                        (select count(l.id) from account_invoice_line as l
153
                         left join account_invoice as a ON (a.id=l.invoice_id)
154
                         where a.id=ai.id) <> 0
155
                       THEN
156
                        (select count(l.id) from account_invoice_line as l
157
                         left join account_invoice as a ON (a.id=l.invoice_id)
158
                         where a.id=ai.id)
159
                       ELSE 1
160
                       END) / cr.rate as residual
161
                from account_invoice_line as ail
162
                left join account_invoice as ai ON (ai.id=ail.invoice_id)
163
                left join product_product pr on (pr.id=ail.product_id)
164
                left join product_template pt on (pt.id=pr.product_tmpl_id)
165
                left join product_uom u on (u.id=ail.uos_id),
166
                res_currency_rate cr
167
                where cr.id in (select id from res_currency_rate cr2  where (cr2.currency_id = ai.currency_id)
168
                and ((ai.date_invoice is not null and cr.name <= ai.date_invoice) or (ai.date_invoice is null and cr.name <= NOW())) limit 1)
169
                group by ail.product_id,
170
                    ai.date_invoice,
171
                    ai.id,
172
                    cr.rate,
173
                    to_char(ai.date_invoice, 'YYYY'),
174
                    to_char(ai.date_invoice, 'MM'),
175
                    to_char(ai.date_invoice, 'YYYY-MM-DD'),
176
                    ai.partner_id,
177
                    ai.payment_term,
178
                    ai.period_id,
179
                    u.name,
180
                    ai.currency_id,
181
                    ai.journal_id,
182
                    ai.fiscal_position,
183
                    ai.user_id,
184
                    ai.company_id,
185
                    ai.type,
186
                    ai.state,
187
                    pt.categ_id,
188
                    ai.date_due,
189
                    ai.address_contact_id,
190
                    ai.address_invoice_id,
191
                    ai.account_id,
192
                    ail.account_id,
193
                    ai.partner_bank_id,
194
                    ai.residual,
195
                    ai.amount_total,
196
                    u.uom_type,
197
                    u.category_id
198
            )
199
        """)

Mon point de vue sur le changement de licence d’OpenERP

Bonjour à tous,

Je vais aujourd’hui vous parler du sujet qui a embrasé la communauté depuis la semaine dernière : L’ajout d’une exception dans la licence AGPL d’OpenERP, permettant potentiellement d’éviter la redistribution du code source via l’achat d’une version Entreprise auprès d’OpenERP SA.

Alors comme tout le monde dans la communauté, sur le coup j’ai été scandalisé :

-On a la création d’une part d’une double licence, ce qui est notre pire frayeur : SugarCRM, Pentaho, Magento, etc… énormément de logiciels libres populaires aujourd’hui et à destination des entreprises ont également en parallèle une version entreprise ce qui implique que tous les efforts ne sont pas fait pour améliorer la version libre et souvent limiter même les efforts de la communauté. C’est l’une des principales forces d’OpenERP à l’heure actuelle que de ne pas être tombé dans ce travers et c’est une très, TRES mauvaise nouvelle que de la voir commencer à pointer le bout de son nez.
Alors ok on nous assure que cette version Entreprise n’a rien à voir avec les autres doubles licences, que l’ensemble des modules continuera à être licencié en AGPL, don’t act j’y reviens plus tard dans ce billet. Il n’empêche que le nom fait très peur.

-On nous parle également d’acheter contre espèce sonnantes et trébuchantes le droit de ne pas redistribuer le code source. Pas vraiment besoin d’être un adepte des théories du complot pour imaginer immédiatement des arrangements entre OpenERP SA et de grosses sociétés afin de faire des entorses aux garanties de la GPL et donc les garanties protégeant la communauté et les utilisateurs.

C’est ce qui nous vient immédiatement à l’esprit lorsque OpenERP SA a présenté sa nouvelle offre, et c’est pour cela que les débats ont été particulièrement virulent la semaine dernière à ce sujet. J’ai moi-même commencé à craindre qu’une partie importante de la communauté ne commence à se tourner vers Tryton.
Mais quand on analyse dans le détail l’offre, on se rend compte qu’elle n’est pas forcément si mal pensée que cela, pour comprendre où je veux en venir laissez moi rentrer dans le détail des licences *GPL.

La première licence *GPL, que je vais passer rapidement car elle n’a jamais été utilisée par OpenERP, et également la moins restrictive est la licence LGPL. Elle sert principalement quand la licence d’un logiciel a besoin d’être compatible avec du code propriétaire tout en pouvant néanmoins protéger par les garanties GPL le logiciel lui-même.

La licence GPL est la licence de base approuvée par la FSF et l’une des plus restrictive. Parfois trop au regard de certaines personnes, car vous ne pouvez utiliser un logiciel sous GPL avec du code propriétaire. Vous avez l’obligation de redistribuer le code source si vous faites une modification sur le logiciel, mais vous pouvez néanmoins créer une extension comme un module OpenERP sans avoir à le publier tant que vous l’utilisez de manière privée. OpenERP est resté longtemps en GPL V2 puis en GPL V3 quand cette version est sortie.

La licence GPL n’apportait néanmoins aucune garantie par rapport au SaaS. Vous pouviez par exemple prendre le code d’OpenERP, créer des modules utiles dont vous gardiez le code et proposer sur cette base un service SaaS payant sans avoir à publier le code source de vos modules. C’est ce que j’appelle une offre SaaS opportuniste, evidemment condamnable en regard de l’esprit du logiciel libre.
C’est pour palier à ce cas de figure que la FSF a créée la licence AGPL. Le principe est simple : vous pouvez demander le code source de tout logiciel que vous utiliser, même si celui-ci est utilisé à travers le réseau. Notez la différence de taille entre la GPL et la AGPL : Si on se place en contexte d’entreprise, cela signifie que même les employés ou les partenaires ayant un accès restreint sur l’ERP peuvent demander le code source de l’OpenERP de l’entreprise, y compris des modules développés spécifiquement pour elle et qu’elle utilise uniquement à titre privé.

OpenERP est sous licence AGPL depuis l’année dernière. C’était de toute évidence nécessaire pour éviter les offres SaaS opportunistes que j’ai évoqué et qui auraient pu apparaitre très rapidement. Imaginez vous prenez le code d’OpenERP, développez une verticalisation par exemple à destination des sociétés de services et vendiez le tout sans avoir à redistribuer votre verticalisation. J’imagine aisément comment ces opportunistes aurait pu apparaitre en quelques années sur le dos d’OpenERP donc c’était de tout évidence une nécessité.

Et donc maintenant OpenERP SA reçoit des demandes de la part d’entreprises souhaitant protéger leurs modules privés (qui peuvent souvent refléter une manière de travailler unique à l’entreprise et dont elle ne veut pas voir profiter sa concurrence). Ce sur quoi OpenERP SA répond aujourd’hui par l’exception de l’offre AGPL.
Cette exception dit que si l’entreprise cliente paye la version entreprise, elle peut ne pas donner le code source de ses modules privés à ses utilisateurs mais doit le donner si elle en distribue des copies (notamment si elle essaye de les revendre) qui reviennent alors immédiatement sous les termes classiques de la AGPL. Pour moi il ne s’agit ni plus ni moins que de vendre le droit d’utiliser la licence GPL plutôt que l’AGPL.

Et pour une fois je ne vais pas planter de couteau dans le dos à OpenERP SA : Je suis d’accord avec eux. Pour moi, les deux licences GPL et l’AGPL protègent les intérêts de la communauté, à la seule exception des offres SaaS opportunistes pour la GPL. Je ne vois aucun problème à autoriser les modules à usage privés dans les entreprises utilisatrices, c’est parfaitement dans l’esprit du logiciel libre, cela a été comme ça pendant toute la période GPL d’OpenERP et je dirait même que l’interdire purement et simplement comme le fait l’AGPL déservirait vraiment les intérêts d’OpenERP et de sa communauté.

Mais là où je trouve vraiment intéressant le choix d’OpenERP SA, c’est qu’ils ont réussi à trouver un modèle économique (le fait de faire payer les entreprises qui veulent protéger leurs méthodes de travail interne), égalitaire (c’est pas toutes les entreprises qui auront besoin d’une telle protection, et celles qui en ont besoin peuvent en payer le prix) et surtout dont la seule différence entre les utilisateurs payants et non-payants est… juste d’imposer une licence plus restrictive encore sur les garanties du logiciel libre, via l’imposition pour les utilisateurs non-payants de la licence AGPL. Des utilisateurs payants ayant un équivalent GPL protégeant déjà correctement les intérêts de la communauté et des utilisateurs non-payants dont la seule restriction est uniquement d’être obligé de publier le code source à ses employés et partenaires… C’est brillant, juste brillant.

Depuis mes débuts sur OpenERP, je craignais que OpenERP SA ne soit obligé finalement d’adopter une double licence pour arriver à survivre, je les ai vu pendant toute la période lutter pour arriver à trouver un business model viable mais respectueux de la communauté. Quand cette exception est arrivée, j’ai cru, comme beaucoup d’autres, qu’ils avaient surtout commencé à jeter l’éponge et à se diriger vers une double licence néanmoins finalement… il semble qu’au contraire ils aient bel et bien réussi à trouver le modèle économique qu’ils cherchaient! Personnellement je soutiens donc cette idée qui est selon moi incroyablement originale.

Étudions maintenant les différents cas de figure :

1)Le cas où une société peu scrupuleuse développe un module et tente ensuite de le vendre sans redistribuer librement le code source. Ce cas ne doit selon moi pas être possible sans violer l’esprit du logiciel libre.

2)Le cas où une société cliente veut développer un module à usage interne exclusivement. La société doit avoir la possibilité, de manière gratuite ou payante, de garder la pleine propriété intellectuelle du module y compris vis à vis de ses employés et partenaires. Ceci ne viole pas selon l’esprit du logiciel libre.

3)Le cas où une société cliente veut avoir accès à un module. Elle doit selon moi pour que soit respecté l’esprit du logiciel libre pouvoir accéder librement au code source de tous les modules développés par l’éditeur, par un intégrateur qui base ses services dessus et ceux utilisés dans une offre SaaS. Ils n’a pas forcément à avoir accès à un module utilisé uniquement en interne dans une autre société.

4)Le cas où une société peu scrupuleuse développe un module pour baser une offre SaaS dessus sans avoir à redistribuer librement le code source. Ce cas ne doit selon moi pas être possible sans violer l’esprit du logiciel libre.

OpenERP sous GPL :

1) Cas impossible sans violer la licence

2) Cas possible sans violation de licence

3) La société cliente n’a pas accès aux modules d’une offre SaaS peu scrupuleuse.

4) Cas possible sans violation de licence

OpenERP  sous AGPL

1) Cas impossible sans violer la licence

2) Cas impossible sans violer la licence

3) La société cliente a correctement accès à tous les modules.

4) Cas impossible sans violer la licence

OpenERP sous AGPL + exception. La société dont il est fait mention dans le cas a acheté la version entreprise.

1) Cas impossible sans violer la licence

2) Cas possible sans violation de licence

3)4) Je ne suis pas sûr… J’ai beau regarder le texte de l’exception, ce qu’OpenERP SA offre aux utilisateurs de la version Entreprise est le droit de ne pas redistribuer le code source aux utilisateurs, sans autre restriction. C’est bien trop proche de la GPL pour empêcher les offres SaaS opportunistes d’apparaitre, il leur suffirait alors juste d’acheter la version Entreprise… OpenERP SA a besoin d’être beaucoup plus explicite sur ce point, et indiquer explicitement que l’exception n’est plus valable si l’accès à l’ERP est payant d’une quelconque manière (Je pense aux offres SaaS opportuniste mais aussi à une société qui ferait payer par exemple une option à ses clients pour qu’ils accèdent à leurs factures sur l’ERP de la société, dans ce cas le code doit être également redistribué).

Qui plus est, il reste deux problèmes à la mise en place de cette licence que je vais juste évoquer rapidement :

-Il y a encore beaucoup de personnes dans la communauté, détentrice de copyright sur le code d’OpenERP, qui refusent d’autoriser le passage à la nouvelle licence. En réaction OpenERP SA veut réécrire leur contribution ce qui est évidemment une sacrée insulte. Je trouve cela infiniment regrettable, même si au final l’idée semble bonne OpenERP SA a voulu passer en force et résultat c’est l’escalade. OpenERP SA ne DOIT PAS réécrire ces contributions, ils ont déjà beaucoup trop tendance à être renfermé sur eux même ce qui n’est pas sain pour un logiciel libre (J’ai déjà suffisamment fait part de mon opinion sur le fait qu’OpenERP SA devrait faire un bien meilleur usage des contributions de la communauté). J’invite tout un chacun à discuter de manière responsable sur le sujet, si il y a des réticences du coté de la communauté, proposez et demandez des garanties.

-Certains membres de la communauté ont mis en avant le fait que les modules AGPL ne serait pas compatible avec l’AGPL+Exception. Ce serait évidement un considérable problème, mais mes compétences juridiques limitées ne me permettent pas de faire plus de commentaires sur le sujet.

En conclusion, mon avis est que je soutient la nouvelle licence, à condition que les offres SaaS opportunistes soit explicitement bannies de l’exception, et j’adresse mes félicitations à OpenERP SA pour avoir trouver ce business model.

PS : Pour les anglophones, je vous invite à lire cet excellent billet sur le même sujet : http://www.qmuxs.com/version2beta/2011/a-new-openerp-product-and-license/.

Update : Depuis l’article et suite principalement à l’insistance de la société Akretion, il semblerait que l’on commence à ce diriger vers la possibilité pour les contributeurs de vendre leur “version entreprise” de leur module : http://www.openerp.com/irc/%23openobject.2011-06-30.log.html#t2011-06-30T23:22:31 . C’est en train de devenir très interessant car du coup non seulement le modèle économique de la licence est interessant mais en plus toute la communauté pourra profiter des retombées économiques! Ceci pourrait potentiellement convaincre la communauté de changer la licence de leurs modules et donc régler ce problème d’incompatiblité.

Bravo et merci Raphael ;).

Nouvelle présentation de notre méthodologie d’intégration

Bonjour à tous,

En ce moment Tiny publie beaucoup de documents, ce qui est plutôt une bonne chose. En début de semaine, un document très intéressant et très bien fait a été publié : un memento sur la méthodologie d’intégration, à destination des partenaires intégrateurs comme nous.

Je dois avouer avoir été surpris par la précision et la qualité du document (la dernière fois que j’ai été surpris de la sorte, c’était le memento technique il y a plus de six mois). En tout cas pour nous à SYNERPGY, qui attachons une grande importance à avoir une méthodologie la plus parfaite possible, ce document a été une véritable mine d’or.

On a déjà récemment complètement refondu notre méthodologie, à coup de schémas BPMN, de maquettes OpenERP et de documents de spécifications techniques. Ce nouveau document a donc été l’occasion de mixer le meilleur de notre nouvelle méthodologie et de celle recommandée par Tiny (ainsi que de se forcer à trouver le temps de la présenter sur le site…).

Vous trouverez donc la présentation de notre nouvelle méthodologie sur le site. Si vous êtes un potentiel client cette présentation devrait vous rassurer, si vous êtes intégrateur n’hésitez pas à vous en inspirer et pourquoi pas nous aider à améliorer nos documents de travail.

Module Stock d’OpenERP : Quantité disponible et affichage des stocks

Bonjour à tous,

Aujourd’hui, la demande d’un client a été l’occasion pour nous d’explorer plus avant le fonctionnement de la gestion des stocks, notamment comment était calculé la quantité disponible et le stock virtuel d’un produit.

Pour ceux qui ne le savent pas, la quantité disponible représente la quantité de produit qui est actuellement physiquement présente dans un emplacement tandis que le stock virtuel représente la quantité qui sera disponible quand tous les fournisseurs auront livré les commandes et quand la société aura livré tous ses clients. Ce dernier est notamment très utile pour les commerciaux ce qui leur permet de déterminer la quantité de produits qu’ils peuvent promettre à leurs clients.

Ces champs sont mis à jour dynamiquement en fonction des mouvements de stocks, que ce soit des produits entrants, expéditions etc…

Le problème qui se posait, c’est que la structure des emplacements ayant été modifiée, les quantités disponibles et stocks virtuels de tous les produits restaient invariablement à 0. Cela nous a poussé à chercher comment étaient calculés ces champs, et notamment quels emplacements de stock étaient considérés par OpenERP comme faisant parti du stock de la société et donc comme produit disponible.

Nous avons d’abord pensé que tous les emplacements ayant le type “emplacement interne” étaient pris en compte, ce qui était faux. Nous avons également pensé qu’il fallait obligatoirement garder les emplacement “Emplacement physique” / “nom de la société” / “Stock” définis par défaut mais c’était faux également.

Ne trouvant pas l’information sur Internet, nous avons dû regarder directement dans le code. L’information se trouve dans le fichier product.py du module stock.

En vérité, ils sont basés non sur les emplacements mais sur les entrepots (stock.warehouse). Ceux-ci ont un emplacement stock et c’est celui-ci qui est utilisé pour le calcul des quantités disponibles du produit. Ainsi, les quantités disponibles d’un produit sont les quantités de ce produit dans tous les emplacement de stock de tous les entrepôt existants.
Si vous avez à modifier vos emplacement de stock, n’oubliez donc pas de renseigner l’emplacement de stock de vos entrepots.

Pour information supplémentaire, sachez que lorsque vous consulter la liste des produits en créant un devis, la liste des produits affiche uniquement les quantités disponibles dans l’entrepot du magasin de la commande, et donc uniquement l’emplacement de stock et ses emplacements fils de cet entrepot. Sur la fiche produit, en revanche tous les entrepots sont pris en compte.

Le client nous a également demandé que seul les produits ayant une quantité différente de zéro (dans le cas du client, seulement 40 produits au lieu de 2000…) soient affichés quand on consulte les produits d’un emplacement de stock. Pour les plus techniques d’entre vous, voici le code qu’on a implanté dans le module stock.

Il vous faut modifier le fichier stock/wizard/wizard_location_product.py et remplacer la fonction _action_open_windows par celle-ci :

def _action_open_window(self, cr, uid, data, context):

self.pool = pooler.get_pool(cr.dbname)
product_obj = self.pool.get(‘product.product’)

product_ids = product_obj.search(cr, uid, [(‘active’,’=’,True)])
prod_context = {‘location': data[‘ids’][0],’from_date':data[‘form’][‘from_date’],’to_date':data[‘form’][‘to_date’]}
products = product_obj.read(cr, uid, product_ids, [‘qty_available’,’virtual_available’], prod_context)

res = []

for product in products:
if (product[‘qty_available’] > 0) or (product[‘virtual_available’] > 0):
res = res + [product[‘id’]]

return {
‘name': False,
‘view_type': ‘form’,
“view_mode”: ‘tree,form’,
‘res_model': ‘product.product’,
‘type': ‘ir.actions.act_window’,
‘context':{‘location': data[‘ids’][0],’from_date':data[‘form’][‘from_date’],’to_date':data[‘form’][‘to_date’]},
‘domain':[(‘type’,'<>’,’service’),(‘id’,’in’,res)]
}

Il n’est pas certain que Tiny accepte ce code car il est très consommateur en ressource système (il doit passer les 2000 produits ayant la case “actif” cochée en revue et calculer leurs quantités disponibles avant de sélectionner ceux qui apparaitront), mais c’est il est vrai une amélioration ergonomique notable que de pouvoir afficher que les produits présents dans l’emplacement consulté.

Sortie du premier processus OpenERP : Gestion des ventes

Bonjour à tous,

Dans l’objectif de toujours améliorer nos prestations et la satisfaction de nos clients, nous continuons à perfectionner nos différents documents de travail, que nous publions comme d’habitude.

Le document qui est publié aujourd’hui n’est ni plus ni moins qu’un diagramme BPMN du processus de vente d’OpenERP. Ces diagrammes, que je nomme “processus génériques” sont notre base de travail quand nous intervenons chez le client lors de la phase d’étude. Attention, par manque de temps le schéma est uniquement en français. Sentez-vous libre de le traduire si vous le souhaitez.

Sur la base de ce diagramme, nous pouvons ensuite l’adapter suite aux remarques du client et modéliser ainsi très précisément le fonctionnement futur de la société cliente sous OpenERP. Ainsi, nous pouvons beaucoup plus facilement repérer lors de la phase d’étude les principaux points que le client voudra voir corriger et lui donner à ce moment là une vision suffisante du fonctionnement futur de sa société.

Pour l’instant seul le processus de vente est modélisé, ainsi que des mini-process de création de partenaires et de produits. Je pense qu’il s’agissait également d’un des plus complexes car il s’agit du processus central, celui qui est relié à pratiquement tous les autres.
J’espère sortir les autres processus rapidement (nous en avons besoin) notamment le processus de facturation, le processus fabrication-stock-achat, le processus projet-comptabilité analytique, processus CRM et enfin processus synchronisation Magento. J’espère (probablement follement) les sortir avant la fin du mois, donc surveillez le site.

Je précise enfin que l’objectif des “processus génériques” est l’exhaustivité. Quand nous intervenons chez le client, l’objectif et de surtout avoir à simplifier le processus et pas l’inverse. Des processus par secteurs d’activités seront plus tard créés sur cette base afin d’affiner l’adéquation des processus et de préparer le terrain pour d’autres types de prestations.

Comme d’habitude, tous nos documents sont disponible sous licence CC by-sa, donc n’hésitez pas à les utiliser, à les modifier si nécessaire et à nous faire parvenir vos améliorations. Notamment si l’éditeur en venait un jour à les utiliser pour les futures versions cela serait génial, mais sinon vous pouvez compter sur nous pour les tenir à jour.
Nous serons juste vigilant sur un point : le respect de la clause attribution. Ne vous amusez pas à retirer notre nom, c’est quand même un gros travail qui est abattu et c’est bien le strict minimum que nous pouvons demander.

Vous pouvez trouver les processus ici : http://www.synerpgy.fr/processus

A très bientôt, je vous prépare une autre surprise pour les prochains jours.

Suggestion d’amélioration au niveau des droits d’accès d’OpenERP

Bonjour à tous,

J’aimerai vous faire part de quelques réflexions que je me fais au niveau du support des droits d’accès dans OpenERP, et comment je pense qu’il serait souhaitable de les améliorer.

Les droits d’accès dans OpenERP sont déjà très bien implémentés, en permettant notamment :
-De mettre des droits d’accès sur les différents menus, ou au niveau de l’action sur lesquels ils pointent.
-De mettre des droits d’accès sur l’objet lui-même, avec droit lecture/écriture/création/suppression.
-De définir des droits sur les champs eux-mêmes, soit au niveau de la vue soit au niveau de l’objet.
-De définir de la segmentation avec un moteur de règles d’accès qui est à mon sens déjà très puissant.

Ces outils permettent selon moi de faire face à une bonne partie des situations où les droits d’accès sont nécessaires, que ce soit si on veut interdire globalement l’accès à un objet, bloquer un menu spécifique, agir sur un champ en particulier ou ne donner accès qu’à une partie des enregistrements d’un objet (une partie des partenaires par exemple).

Il y a toutefois un cas qui n’est pas couvert, et je pense que les besoins des entreprises sont tels que ce cas pourrait se révéler très rapidement bloquant. Ce cas c’est la dualité lecture/écriture sur les droits d’accès.

Certes on le retrouve au niveau des objets, mais pas au niveau des droits des champs ou au niveau des règles d’accès.
Ainsi, si on met un droit sur un champ, alors ce champ disparait de l’interface de l’utilisateur n’ayant pas les droits même si on aurait voulu qu’il conserve un droit en lecture sur le champ et que seul le manager ait le droit en écriture.
De même, si par exemple un utilisateur ne remplit pas les conditions pour les règles d’accès sur un enregistrement de partenaire, alors il ne pourra même pas consulter l’enregistrement en lecture.

Pourtant, le cas où une entreprise a besoin de donner accès en lecture au plus grand nombre à une information tandis que seuls quelques personnes peuvent le modifier est très courant.
Par exemple, imaginer les commerciaux qui ont accès aux devis de la gestion des ventes. Aujourd’hui, tous ont accès en écriture aux devis de tous les commerciaux, alors que normalement ils ne devrait avoir accès en écriture qu’à leurs devis, et en lecture sur les autres car ils peuvent avoir le client d’un autre commercial au téléphone et avoir besoin de consulter l’offre qui lui a été faite.
Je pense ainsi que c’est une amélioration importante à effectuer sur le coeur d’OpenERP, OpenObject.

Je propose de remplacer le many2many des droits d’accès au niveau des droits des éléments des vues, des champs des objets et des règles d’accès par deux many2many, l’un qui renseignerai les groupes ayant le droit en lecture et l’autre qui renseignerai les groupes ayant le droit en écriture sur le champ ou l’enregistrement.

Bien entendu, le principe de cumul qui prévaut dans le système de droit d’OpenERP s’applique aussi ici.
Si l’utilisateur est membre d’un ou plusieurs groupes ayant le droit en lecture, il aura le droit en lecture. (Je précise que le droit en lecture n’est pas suffisant pour activer les boutons de workflow de l’enregistrement, par exemple confirmer une commande de vente)
Si il est membre d’un groupe ayant le droit en lecture et un autre ayant le droit en écriture sur le même champ ou enregistrement, alors il aura le droit en écriture.
Si il n’est membre d’aucun groupe ayant au moins le droit en lecture, le champ n’apparaitra pas sur son écran.

Il s’agit réellement du seul reproche que je peux faire à l’actuel système de droit d’accès. Avec cette correction, je pense que il n’y aura plus une seule situation où le système de droit d’accès ne sera pas capable de faire face.

J’ai déjà transmis mes remarques à Tiny, attendons de voir ce qu’ils en pensent. En attendant, n’hésitez pas à réagir dans les commentaires.

Lancement du nouveau site de Synerpgy

Bonjour à tous,

C’est avec plaisir que je vous annonce le lancement du nouveau site de la société Synerpgy : www.synerpgy.fr .

Nous avons la volonté d’exposer nos travaux et nos compétences, et ce nouveau site internet est un grand pas en avant pour y parvenir. Désormais, l’ensemble de nos documents internes seront publiés sur le site, à commencer bientôt par notre mindmap sur les modules OpenERP, notre procédure d’installation d’OpenERP ainsi que nos premiers plans de formations, les plans de formations Technique et de Comptabilité.

Précisons que l’ensemble du site sera sous licence Creative Common by-sa. Nous sommes des passionnées du logiciel libre, et nous assurons cette cohérence jusqu’au bout.

Enfin, les articles venant de nos blogs ou de la communauté OpenERP seront agrégés sur le site, dans l’objectif d’en faire également un site d’information sur la communauté OpenERP.

Sur le plan technique, le CMS WordPress a été remplacé par un CMS Drupal qui dispose de bien plus de fonctionnalités dont nous avons besoin. Citons entre autre la gestion des flux RSS avec de puissantes fonctions d’affichage, la gestion des contributions avant publication par un administrateur, connecteur LDAP etc… Le tout avec une incroyable flexibilité et des modules parfaitement intégrés les uns aux autres, c’est vraiment le CMS que nous recommandons pour des projets de sites internet un minimum ambitieux.

Le site internet nous a pris beaucoup de temps et c’est pour cela qu’il y a eu peu de billet ces derniers temps. J’espère que le rythme sera plus soutenu à partir de maintenant.

A très bientôt.

Comparatif des fonctions RH entre OpenERP, Ofbiz et ERP5

L’un de nos clients est en train de comparer différentes solutions libres pour des besoins de comptabilité et de gestion des ressources humaines, entre OpenERP, Ofbiz et ERP5.

OpenERP a la préférence du client au niveau de sa base technologique. Sa gestion de la comptabilité n’est pas remise en question et n’influe donc pas sur le choix. En revanche des doutes ont été émis sur la force de sa gestion des Ressources Humaines. Il s’agit ainsi de la raison de ce comparatif, afin de comparer les fonctions de gestion des Ressources Humaines à Ofbiz et ERP5 et éventuellement identifier des améliorations possibles.

Comparaison avec Ofbiz :

1ère chose très intéressante avec Ofbiz : Dès l’arrivée dans le module RH on voit directement la liste des différents départements.

1-Ofbiz Accueil RH

Il devrait en être de même dans OpenERP, même si celui-ci gère bel et bien les départements

2-OpenERP Structure Département

Mais ils n’apparaissent pas directement sur la page d’accueil de la partie RH. Dans l’idéal, un nouveau menu devrait apparaître dans le menu RH pour chaque département de l’entreprise, et mènerait vers un tableau de bord du département comme sur Ofbiz (actuellement elle ne mène que vers la liste des employés) :

3-Ofbiz Tableau de bord département

Bon en vérité, je ne comprend absolument pas en quoi ce tableau de bord est en rapport avec de la RH. J’ai l’impression que les départements dans Ofbiz sont un contact et que ce sont des informations de contact qu’on a là.

Bref, pourquoi j’en parle alors? Parce que j’aime l’idée d’avoir la liste des départements accessible directement depuis le menu RH et que cela mène à un tableau de bord adapté à une utilisation RH. Il nous faudra juste déterminer ce qu’on met dans ce tableau de bord.

On notera que bien que la page en elle même est relativement inutile, on a des onglet en haut tel que les emplois, positions d’employés, compétences, qualification, formation et congé qui sont je pense liés au département. Cela donne de bonne pistes de réflexions.

Créons un nouvel employé dans Ofbiz :

4-Ofbiz Création Employé

Les informations sont assez classiques, et OpenERP gère parfaitement bien les informations d’employé, certainement mieux qu’Ofbiz :

5-OpenERP Fiche Employé

On notera le champ « Responsable » qui permet de créer une structure hiérarchique des employés :

6-OpenERP Structure Employés

Concernant la gestion des listes d’employés, OpenERP n’a donc rien à changer et le gère parfaitement bien.

De retour sur Ofbiz, la fiche employé est un peu plus complète (utilisateur ofbiz par exemple, salaire) mais tout de même moins que celle d’OpenERP (Responsable? Numéro de Sécu?).

7-Ofbiz Fiche Employé

On remarquera à nouveau les onglets en haut, je suppose que c’est une fonction de base d’Ofbiz que d’afficher les enregistrements en rapport avec l’objet consulté. OpenERP le fait aussi mais d’une autre manière (liens sur la droite qui ouvre un popup).

OpenERP a sans doute à gagner à remplacer les liens à droite par une consultation directe des liens en rapport avec l’enregistrement consulté sans ouvrir de popup (ajax?) avec un bouton pour revenir à la fiche initiale.

A ce stade de la rédaction de l’article, les conclusions commencent à apparaître et j’ai suffisamment d’éléments pour mon client. Je dois réserver mon temps car je souhaite faire bientôt un plus important comparatif au niveau de la gestion commerciale d’OpenERP, je vais donc présenter rapidement le reste du comparatif avec Ofbiz, et j’essairais d’étoffer le comparatif plus tard.

Ofbiz implémente une gestion de la disponibilité des postes, là où OpenERP implémente un suivi des affectations des utilisateurs mais pas sur la disponibilité des postes en eux-mêmes. Cela reste facilement implémentation.

Ofbiz implémente toute une gestion des compétences et qualifications qu’OpenERP n’implémente que simplement (attention, je n’ai pas fait de comparatif poussé là dessus). Pareil cela peut s’améliorer facilement. Pareil pour le suivi de la performance de l’employé et des formations.

Ofbiz et OpenERP implémentent tout deux une gestion poussée des congés. OpenERP implémente en plus la gestion des notes de frais, contrairement à Ofbiz.

Implémentation des recrutements pour les deux, mais OpenERP utilise le moteur de CRM pour le suivi, ce qui a ses bons et mauvais coté.

En conclusion, OpenERP et Ofbiz sont deux très bon logiciels pour la gestion RH. Je reconnais que la qualité du module RH d’OpenERP est moindre que le module de Stock par exemple, mais il reste tout à fait intéressant.

De l’autre coté, on sent que Ofbiz a fourni plus de travail sur l’implémentation de la RH mais malgré cela OpenERP n’est pas loin derrière quand on prend en compte des modules issus de la communauté, et il rattrapera aisément son retard si quelqu’un s’y mettait sérieusement.

Enfin, OpenERP a pour lui la gestion des feuilles de temps ce qui n’est pas rien, et surtout le fait que la paye est sur le point d’être intégré contrairement à Ofbiz. Ce simple point est suffisant pour faire pencher la balance.

Voici mes commentaires par rapport à ERP5 :

Mise à jour : On me signale fort justement dans les commentaires que mon analyse sur ERP5 est faussé pour une simple raison : Le module RH n’est pas installé sur la version gratuite dont je me servais pour mes tests, ce dont je ne me doutais pas. Je vous invite à consulter les commentaires pour plus de précisions.

Voici l’écran d’accueil :

8-ERP5 Accueil

Il y a quand même des choses qui frappent ici. Notamment l’absence d’une partie Ressources Humaines. Les seuls menus que je vois pour la gestion RH c’est Organisations et Personnes.

Concernant l’organisation, j’ai retrouvé uniquement le nom de la société ici. On peut éventuellement s’en servir pour créer des départements mais je ne pense pas que ce soit optimisé pour cet usage, ne serait-ce parce qu’il n’y a pas de gestion des départements parent, empêchant donc une gestion avancée d’une structure hiérarchique. Par contre au moins, on retrouve la liste des personnes de l’organisation :

9-ERP5 Organisation

Concernant la gestion des employé, on retrouve les informations tels que les coordonnées, l’organisation (et du coup il ne peut pas appartenir à plusieurs organisations ou départements…) et on peut lui définir sa fonction en choisissant dans une liste :

9-ERP5 Employés

On a quand même une gestion des affectations, mais sans gestion de la disponibilité ou du salaire (même un simple champ).

10-ERP5 Affectation

11-ERP5 Affectation

En résumé, gestion des employés et des départements inférieure à OpenERP et Ofbiz, pas de gestion des recrutements, des compétences, des congés, des notes de frais, et ne parlons même pas de la paye. Je pense que je n’aurai pas trop de problèmes à convaincre mon client de 250 employés que la solution n’est pas adapté.

Je vais quand même pas trop casser du sucre sur ERP5, le logiciel me semble suffisamment simple pour convenir parfaitement pour une TPE (OpenERP a encore à progresser sur la simplicité de la gestion commerciale, cela fera l’objet d’un futur article) mais là très clairement il ne sera pas adapté à une PME avec un certain nombre de personne.

Enfin voici les fonctions d’OpenERP qu’on ne retrouve pas dans aucun des deux logiciels :

OpenERP dispose d’une gestion des Feuilles de Temps impressionnante, parfaitement intégrée à la gestion de projet et des comptes analytiques. Malheureusement pour nous, le client n’est pas intéressé mais il est impossible pour nous de clore cette étude sans citer cette fonctionnalité.

Il supporte également la gestion des notes de frais, avec intégration directe avec la comptabilité.

Enfin, et surtout, il est le seul à être sur le point d’implémenter la gestion de la paye, et c’est quand même la fonction la plus importante attendue de la part d’un module RH.

Conclusions :

ERP5 est éliminé selon moi de l’équation, cela se joue entre OpenERP et Ofbiz. Ofbiz a une certaine avance sur certaines fonctionnalités, mais pas si importante et pêche sur certains points. Je n’aurai pas trop de mal à recommander OpenERP à mon client sur la base d’une couverture fonctionnelle satisfaisante pour son besoin, d’une amélioration qui ne sera pas très difficile à faire pour rattraper Ofbiz, et l’implémentation de fonctions uniques tel que les notes de frais et surtout la paye.

Droit de réponse : J’ai tendance à afficher très violemment mon avis quand je compare deux logiciels, et si je suis expert en OpenERP je ne le suis pas en Ofbiz et ERP5. Cette analyse est biaisé, et je l’assume.

Conformément à la loi et même si ça n’avait pas été le cas, des pro-Ofbiz et pro-ERP5 ont droit de réponse ici si ils souhaitent apporter des compléments d’informations ou corriger certaines de mes affirmations.

Blueprint pour une amélioration des règles de promotion dans OpenERP

Sharoon Thomas, qui a fait les excellent modules poweremail et magentoerpconnect, semble être intéressé pour améliorer les outils de règles de promotion dans OpenERP.

Pour lui donner un coup de main, j’ai fait une rapide analyse pour lui, en particulier une comparaison avec le moteur de promotion très puissant de Magento. Finalement on dirait que les conlusions étaient faciles à trouver, OpenERP a un moteur pour les règles qui sont basé sur les informations produits, mais en revanche totalement inexistant pour des règles basées sur le contenu d’une commande . Je supose qu’une implémentation dans ce domaine pourrait être une importante amélioration.

Voici mon analyse (en anglais, désolé la flemme de traduire tout le document) :

Improvement of the promotion rule in OpenERP

Introduction

The goal is to improve the promotion rule tool in OpenERP. Magento has a great system for this purpose, so we’ll make a comparison with it.

Modules that already exist

A quick search in the module list show the module that might be useful :

1)discount_campaign

The goal of this module is to manage a refund system. It might be useful if for example we want to give a 5% discount if a customer buy more than 50 product A in 2009.

At least, this is my comprehension, as there is no real description. The idea is good, but I think the module should still be improved.

2)product_pricelist_discount_and_tax

This module improve management of tax at pricelist and do some control. According to me, it’s certainly a module that should be merge with the core module product, but it don’t implement a very new functionality, except management of visible discount and the possibility to specify if tax included or not.

3)sale_target_discount

This module improve the usability of the sales management by allowing to specify directly the price with the discount.

Comparison with Magento

Catalog Price Rule

The Catalog Price Rule at Magento manage the rule which are product-based. Each rule can be apply on each customer group.

At OpenERP, each Partner can have several Partner, so the way to implement the promotion are different. A meta-rule call listprice is define and possess several rule in it, we can also define an availability period. Next, we define what listprice apply to a Partner.

About the Conditions, on Magento, each field (attribute) of the product can be used as a base for a rule, so that we can use name, category but also price, tax etc… This base is next compare (equal, greater, lesser etc…) to a value or a list defined.

On OpenERP, we are limited to only a product or a category of product.

About the Action, Magento can only apply a fix or percentage amount of discount on the price.

OpenERP can apply a fix or percentage amount but also with rounding method and verification of the margin, on the sell price but also the buy price or even another list price.

Conclusion :

At the catalog price rule, Magento and OpenERP are equivalent even if Magento can base the conditions on all field of the product.

So this is the only improvement I suggest, to base condition on all field of product.product and product.template but I think the needing is limited.

Shopping Cart Price Rule

As the Catalog Price Rule, Shoping Cart Price Rule can be applied to customer group, so if an improvement will be done here, I suggest to do it in the listprice of OpenERP.

Magento has also here management of coupon. It’s perhaps the voucher in OpenERP, I don’t know.

We can define the total number of use or the per customer use of a coupon. It’s an interesting function, but I suggest to create a separated module for it, if it’s not already exist.

About Conditions, Magento can do a lot of things :

Attribute combination : It is a condition that will control each field of each product on the cart. For example, if no product contain a price greater than 100€, so the condition is true. Really interesting and no equivalent in OpenERP.

Product subselection : The condition will see if the total amount or quantity of only product that match some subconditions are equial/greater/lesser than a certain number. For example, if between the products that are bought, there are for more than 100€ of product that are considered out-dated (not ever produced), so the condition is true. Really interesting and no equivalent in OpenERP.

If any of the subtotal, quantity total, weight, payment method etc… Equal to a certain value, then condition are true. Basic, but it is still a leak in OpenERP.

About action :

We can apply a fixed or percentage amount of discount per product, or for the whole cart. We can also apply a “Buy Y have X free” rule or free shipping. All of this apply on each product or product that are determined by conditions bases on their field.

Conclusion : None of all of these exist in OpenERP, there is no Shopping Cart Price Rule functionality. At the contrary, the Magento one was just really powerful, just perfect.

I really suggest to implement a module that will implement it the same way as Magento, even by copying the way it is implemented.

Conclusion

It seams that finally conclusion was easy to find, Magento show us the way of the functionality, we should just implement as in Magento.

For the moment I don’t push far further the analysis, feel free to contact me if you need more help.