mardi 15 mai 2012

Quelques commandes MySQL

Voici quelques commandes MySQL basiques, mais qui peuvent être utiles.

But: Se connecter à MySQL.
Commande:
mysql -u user_name -p [database_name]


But: Créer une DB et donner les droits d'accès.
Commandes:
mysql -u root -p
mysql> create database database_name;
mysql> grant all privileges on database_name.* to user_name;


But: Faire un dump d'une DB.
Commande:
mysqldump -u user_name -p database_name > /path/to/dump.sql


But: Restaurer un dump d'une DB.
Commande:
mysql [--verbose] -u user_name -p database_name < /path/to/dump.sql

lundi 30 avril 2012

Format des comptes bancaires dans le footer

Je viens d'apprendre quelque chose de nouveau dans OpenERP 6.1: il est facilement possible de changer la mise en forme d'un compte bancaire, affiché dans le footer d'un rapport.

Problème: changer la mise en forme d'un compte bancaire afin de l'imprimer dans le footer d'un rapport.

Solution: aller dans le menu Ventes / Configuration / Carnet d'adresses / Types de compte bancaire* et choisir le type à modifier. Ensuite, modifier le champ Format de mise en page* pour le faire correspondre à ce que vous souhaitez.

* La traduction d'OpenERP étant incorrecte, j'ai traduit de l'anglais au français comme je l'entendais.

PostgreSQL pg_dump de la version 9.1 à la 8.4

J'y ai passé quelques heures et je n'ai pas encore la solution: comment faire un dump d'une DB postgres 9.1 vers un serveur en version 8.4. Si quelqu'un passe par ici et a la solution, merci de m'expliquer rapidement. Sinon, je posterai quans j'aurai trouvé !

OpenERP bloqué (HTTPS)

Je viens de passer 45 minutes à essayer de comprendre pourquoi OpenERP démarrait mais était inaccessible. Et je sais qu'un jour je vais reproduire cette erreur, et que je chercherai encore pendant 45 minutes pourquoi ça ne marche pas ! Donc je note le problème, et la solution...

En fait, il y a quelques jours, j'ai essayé d'activer le HTTPS sur OpenERP 6.1. Malheureusement, j'ai eu quelques problème avec mon certificat fait maison (le SSL est loin d'être ma spécialité), et j'ai donc laissé cela de côté. Aujourd'hui après avoir fait une modification sur le serveur, j'ai redémarré ce dernier. Mais j'avais oublié toutes les modifications faites pour tester le SSL.

Pour activer le HTTPS, j'avais ajouté les lignes suivantes au fichier de configuration.


xmlrpc_interface = 127.0.0.1
netrpc_interface = 127.0.0.1

Une fois redémarré, ces lignes ont empêché OpenERP de démarrer convenablement. Le log indiquait le problème, qui n'en est pas vraiment un. Je suis donc passé plusieurs fois au dessus avant de m'en rendre compte.


2012-04-30 09:04:21,083 24095 INFO ? openerp: OpenERP version 6.1-1
2012-04-30 09:04:21,083 24095 INFO ? openerp: addons paths: /usr/lib/pymodules/python2.6/openerp/addons
2012-04-30 09:04:21,083 24095 INFO ? openerp: database hostname: localhost
2012-04-30 09:04:21,083 24095 INFO ? openerp: database port: 5432
2012-04-30 09:04:21,084 24095 INFO ? openerp: database user: ????????
2012-04-30 09:04:21,084 24095 INFO ? openerp.service.netrpc_server: starting NET-RPC service on 127.0.0.1:8070
2012-04-30 09:04:21,085 24095 INFO ? openerp.netsvc: Starting 1 services
2012-04-30 09:04:21,120 24095 INFO ? openerp.wsgi.core: HTTP service (werkzeug) running on 127.0.0.1:8069
2012-04-30 09:04:21,205 24095 INFO ? openerp.addons.web: embedded mode
2012-04-30 09:04:21,549 24095 INFO ? openerp: OpenERP server is running, waiting for connections...

Problème: OpenERP est démarré mais inaccessible.

Cause: OpenERP écoute sur la mauvaise interface.

Solution: Vérifier le fichier de configuration d'OpenERP, et modifier/supprimer les lignes xmlrpc_interface = 127.0.0.1 et netrpc_interface = 127.0.0.1 afin qu'OpenERP écoute sur la bonne interface.

Changer le fuseau horaire d'un serveur

Pour qu'un serveur soit à l'heure, il faut deux chose:

  1. Régler la bonne heure (un serveur NTP peut aider !)
  2. Etre dans le bon fuseau horaire (parce que l'heure local est ajustée en fonction de celui-ci)

Je ne parlerai pas du NTP, mais du réglage du fuseau horaire. C'est tout bête, mais j'oublie constamment cette commande...

Problème: régler le fuseau horaire d'un serveur Ubuntu.

Solution: utiliser la commande: dpkg-reconfigure tzdata

mercredi 25 avril 2012

Liste des menus et leur XMLID pour OpenERP

Faire le réglage de la sécurité dans OpenERP, c'est assez merdique ! Surtout quand il y a une série de menus qui ne devraient pas être visibles et qui le sont !

Problème: lorsqu'on crée un utilisateur dans OpenERP avec des droits particuliers, il arrive qu'il reste des menus visibles alors qu'on ne le souhaite pas.

Cause: certains menus ne sont liés à aucun groupe et sont donc visible par tous les utilisateurs pour peu qu'ils aient des droits en lecture sur l'objet concerné.

Solution:

  1. modifier le menu afin de l'affecter à un groupe au moins.
  2. faire en sorte que les utilisateurs qui ne doivent pas voir ces menus ne soient pas dans ces groupes.

Malheureusement, cette solution n'est pas permanente, c'est-à-dire qu'il faut la refaire sur chaque DB. Pour éviter cela, le mieux est de faire un fichier XML qui modifie les menus simplement en installant un module. Ce fichier pourrait par exemple contenir le code suivant.


<?xml version="1.0" encoding="utf-8"?>
<openerp>
    <data>
        <record id="mygroup" model="res.groups">
            <field name="name">My Group</field>
        </record>

        <!-- Ventes / Configuration -->
        <record id="base.menu_base_config" model="ir.ui.menu">
            <field name="groups_id" eval="[(4, mygroup)]"/>
        </record>
    </data>
</openerp>

Dernier problème: trouver les XMLID de tous les groupes à cacher! Je reconnais que la tâche peut être fastidieuse.
Mais je suis la pour vous aider: ce fichier est un script Python qui génère une liste (et/ou un arbre, au choix) des menus et affiche l'XMLID de chacun.
Son usage est relativement basique mais assez simple:

  1. Ouvrez le fichier avec votre éditeur préféré,
  2. Modifiez la ligne 89 pour indiquer les paramètre de votre DB,
  3. Commentez la ligne 92 ou 93, pour avoir soit l'arbre, soit la liste (optionnel),
  4. Exécutez le script (python openerp_menu_list.py).

Changer le hostname d'un serveur Ubuntu

Lorsque l'on a plusieurs serveurs, on a vite tendance à leur trouver un petit nom... C'est plus parlant qu'un adresse IP. Dès lors, il peut également être intéressant de change le hostname du serveur. Comme cela, lorsqu'on travaille dans un terminal, il est assez facile de voir le serveur sur lequel on est.

Problème: Modifier le hostname d'un serveur Ubuntu.

Solution: Editer le fichier /etc/hostname et y indiquer le nom souhaité.

vendredi 20 avril 2012

Problème d'installation d'un module Prestashop

Aujourd'hui, j'ai du installer quelques modules pour Prestashop, dont certains modifiés par mes soins au préalable. Lors de mes tests, l'installation s'était déroulée sans problème. Cependant, comme une mise en production ne se déroule jamais comme prévu, un de mes modules a refusé de s'installer. Après plus d'une  heure de recherche (problème de copie, erreur PHP, problème de nom de fichier, ...) j'ai fini par trouver l'origine du problème.

Problème: un module Prestashop refuse de s'installer.

Cause: la fonction d'installation du module crée un nouveau hook dans la base de données. Cependant, comme il s'agit d'un module existant modifié, le hook existe déjà. Il n'est donc pas possible d'ajouter le hook.

Solution: modifier la fonction d'installation afin d'appeler la fonction de désinstallation avant d'installer le module.

mardi 17 avril 2012

Héritage PHP

Je travaille actuellement avec Prestashop, et pour les besoins d'un client, je m'occupe de surcharger certaines classes et certains controllers.

Dans l'un des controllers, j'ai était confronté à un problème que je n'avais encore jamais eu: appeler une fonction dans une classe ancêtre, sans passer par le parent... Le tout, sans modifier ni le parent, ni l'ancêtre.

Un peu de mal à comprendre ? Utilisons un exemple: imaginons que l'on ait trois classes: A, B et C. Les classes A et B ne peuvent être modifiées. La classe C hérite obligatoirement de B.


class A {    
    public function fct($param) {
        $result = $param + $param;
        return $result;
    }
}

class B extends A {
    public function fct($param) {
        $result = parent::fct($param);
        return $result + $param;
    }
}

class C extends B {
    public function fct($param) {
        // Doit retourner ($param + $param) * $param; // C'est-à-dire fct($param) dans A, * $param
    }
}

Problème: appeler la fonction fct de la classe A, sans passer par la classe B.

Solution: PHP est génial! C'est prévu dans la version 5.3.2. Il faut juste mettre le nom de la classe avant d'appeler le parent.


class C extends B {
    public function fct($param) {
        $result = A::fct($param);
        return $result * $param;
    }
}

Et voilà: on bypass la classe B aussi simplement que ça !

mardi 10 avril 2012

Compta OpenERP, TVA intra-communautaire

Actuellement, mon collègue et moi travaillons sur un module permettant d'exporter la comptabilité d'OpenERP vers Winbooks. Bien entendu, comme les deux ne fonctionnent pas de la même façon, nous avons du surmonter quelques difficultés, dont la TVA intra-communautaire.

Gérer une TVA intra-communautaire est presque équivalent à utiliser une TVA de 0%.
Et c'est à ce moment que les façons de travailler d'OpenERP et de Winbooks divergent. Alors que Winbooks a besoin d'une écriture comptable indiquant qu'il s'agit d'une TVA de 0%, OpenERP ne se fatigue même pas à créer une entrée dans le journal. Résultat, au moment de l'import vers Winbooks: ERREUR !

Problème: dans OpenERP, il manque une écriture comptable pour indiquer qu'il y a une TVA à 0%.

Solution: pour une fois, OpenERP a prévu le coup et ne requiert pas de modifier le coeur du système... En effet, il existe un hook, c'est-à-dire une méthode prévue pour être surchargée, qui est appelée juste avant que les "account.move.line" ne soient créées.


def finalize_invoice_move_lines(self, cr, uid, invoice_browse, move_lines):
    """finalize_invoice_move_lines(cr, uid, invoice, move_lines) -> move_lines
    Hook method to be overridden in additional modules to verify and possibly alter the
    move lines to be created by an invoice, for special cases.
    :param invoice_browse: browsable record of the invoice that is generating the move lines
    :param move_lines: list of dictionaries with the account.move.lines (as for create())
    :return: the (possibly updated) final move_lines to create for this invoice
    """
    return move_lines

Nous avons donc surchargé cette méthode afin d'ajouter une écriture comptable et résoudre notre problème:


# -*- coding: utf-8 -*-
##############################################################################
#    This module is developed by Idealis Consulting SPRL    
#    Copyright (C) 2011 Idealis Consulting SPRL (). All Rights Reserved
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see .
##############################################################################

from osv import fields, osv
from datetime import time, datetime

class invoice(osv.osv):
    _inherit = 'account.invoice'
    
    def finalize_invoice_move_lines(self, cr, uid, invoice_browse, move_lines):
        """finalize_invoice_move_lines(cr, uid, invoice, move_lines) -> move_lines
        Hook method to be overridden in additional modules to verify and possibly alter the
        move lines to be created by an invoice, for special cases.
        :param invoice_browse: browsable record of the invoice that is generating the move lines
        :param move_lines: list of dictionaries with the account.move.lines (as for create())
        :return: the (possibly updated) final move_lines to create for this invoice
        """
        if invoice_browse.fiscal_position and invoice_browse.fiscal_position.id != 1:
            account = False
            if invoice_browse.journal_id.type in ['sale', 'sale_refund']:
                account = self.pool.get('account.account').search(cr, uid, [('code', '=', '451000')])
            elif invoice_browse.journal_id.type in ['purchase', 'purchase_refund']:
                account = self.pool.get('account.account').search(cr, uid, [('code', '=', '411000')])
                
            if account:
                line = {
                    'name': invoice_browse.name or '/',
                    'partner_id': invoice_browse.partner_id.id,
                    'journal_id': invoice_browse.journal_id.id,
                    'account_id': account[0],
                    'invoice': invoice_browse.id,
                    'debit': 0.0,
                    'credit': 0.0,
                    'quantity': 1,
                    'tax_amount': 0.0,
                    'amount_currency': 0,
                }
                move_lines.append((0, 0, line))
        return move_lines
invoice()

mercredi 4 avril 2012

Qui suis-je ? Pourquoi j'ai créé ce blog ?

Qui suis-je ?

Mon nom est Yves Hoyos. J'habite dans le Hainaut, en Belgique et je travaille en tant que consultant IT.

J'ai fait mes études à l'Université de Mons, en Belgique. J'y ai obtenu un diplôme de Master en sciences informatiques.

Pourquoi j'ai créé ce blog ?

Je ne suis pas du genre à mémoriser beaucoup de choses, je préfère les noter ou dire "oui, j'ai retenu" et oublier deux minutes plus tard.

En tant qu'informaticien, j'ai souvent besoin de trouver des astuces pour le développement, ou des solutions aux erreurs que je peux rencontrer quand je code. Généralement, je recherche ce dont j'ai besoin sur Google, mais dans certains cas, faire cette recherche peut prendre du temps. J'ai donc créé ce bloc dans le but de noter mes astuces et recherches.