sept 20

15 points à vérifier avant une mise en production Magento

  1. Désactiver le mode DEBUG de Magento, véritable gouffre à performance
  2. Réactiver ses Caches (Magento & Reverse proxy) souvent désactivés lors de la phase de développement
  3. Passer les vérifications du W3C (http://validator.w3.org/ et http://jigsaw.w3.org/css-validator/). Un site ne doit pas comporter d’erreurs HTML ou CSS pour être optimal et ne pas pénaliser ses performances, notamment l’interprétation des navigateurs web.
  4. Demander à son hébergeur si toutes les optimisations basiques sont activées de son coté (ramdisk ou memcached pour les sessions, APC, Zend server ou Eaccel pour l’opcode caching de PHP, etc.)
  5. Vérifier ses résultats sous Pagespeed (80% est un minimum à atteindre)
  6. Vérifier le chargement de la page sous dragonfly, firebug ou chrome
  7. Passer un crawler de 404, histoire de ne pas laisser des ressources inaccessibles (vérifier les erreurs 500 dans les logs apache également)
  8. Vérifier ses Cron et leurs temps d’éxécution
  9. Toujours avoir un backup et intégrer sur la préprod
  10. Ne jamais faire sa migration un vendredi soir ou un Week End
  11. Lancer le site au moins une semaine avant toute opération importante, surveiller son fichier system.log dans [site Magento]/var/log/system.log
  12. Faire une vraie recette de son site avant de passer en production, chaque fonction doit être vérifiée
  13. Monter en puissance progressivement (pas de mailing de 180000 personnes sur un site tout frais)
  14. Surveiller ses consoles de supervision pour voir si les serveurs ne montent pas au plafond d’un coup en charge
  15. Surveiller ses slow requests Mysql pendant une petite semaine (c’est un peu couteux en performance, il parait donc important de ne pas le laisser en permanence)

écrit par Philippe Humeau \\ tags: ,

avr 22

Quelques optimisations


A la suite d’Imagine US et des technical tracks ainsi que de plusieurs lectures récentes, je vous propose quelques informations ou techniques que j’ai trouvé intéressantes.

J’allais également oublier, les slides de ma conférence à Imagine sont disponibles ici et la vidéo a été mise en ligne ici.

Zend asynchronous

Lors des tech tracks d’Imagine, j’ai aussi pu voir le passionnant papier de Kevin de Zend. Le principe est de faire des requêtes qui seront servies de manière Asynchrone, ni plus ni moins qu’un Job manager en fait. actuellement je recommandais l’usage de Gearman pour la plupart de gestions de Queue mais quand on a pas besoin d’un fonctionnalité aussi avancé, Zend Asynchronous peut être une ressource à la fois simple et efficace.

Le papier de Kevin est disponible ici.

Mysql, ca ne se scale pas…

On commence de plus en plus a avoir des sites énormes en hébergement. Que ce soit du Ecommerce ou des médias, un gros site va très clairement faire chauffer la base de données. Le soucis avec Mysql, largement reporté déjà mais visible entre autre dans ce thread sur le forum Mysql, c’est que InnoDB et MyISAM se scale très très mal.

Quand on a un serveur qui a plus de 4 processeurs (plus de 4 cores pour être précis), Mysql ne sait pas en tirer partie. Pire, c’est même parfois un handicape. Alors en attendant la version 5.4 qui nous promet une refonte massive de l’architecture multi thread de Mysql, on va devoir faire avec. En plus, depuis le rachat de Sun par Oracle et la politique mené par ce dernier, doublé du mouvement NoSQL, il n’est pas certain qu’on voit un jour cette version.

Pire, avec Oracle derrière, le principe de limitation de Mysql pourrait même faire les affaires du titan qui aurait un intérêt évident à ne pas corriger ce point afin de vendre de l’Oracle.

Alors il reste le moyen de chainer les serveurs à 4 cores… Master/Master/Master etc. Ou de séparer les Read et Write et on fait un Master / Slave. Mais rien de bien brillant pour des sites qui consomment de plus en plus de ressources.

La conception, encore et toujours

Shawan mon amour

On a eu un problème assez original il y a quelques semaines à NBS System. Un client a eu des soucis délirant de charge de sa base de données. Tout le monde s’est posé la question, Moooo gento ou problème plus technique ?

Une première réponse au problème a été une découverte (faite par la web agency), d’un soucis atypique… Quand on fait un mailing pour une vente privée ou des clients existants, il est possible de les authentifier automatiquement quand ils suivent le lien. C’est très confortable pour eux et plusieurs systèmes existent qui facilitent la vie des intégrateurs.

Oui mais…

Quand on fait ca sur une très large clientèle, selon la façon de le faire, cela peut avoir des incidences très sensibles. L’exemple ici c’est que la base de données se retrouvait à décoder des centaines de Shawan (Hash SHA1) à la secondes au moment du pic d’ouverture des mailings. Résultat, à chaque clic, la DB devait décoder le SHA1 et vérifier son authenticité et … ca la cassait en deux.

Ce travail doublé du travail normal de DB la mettait totalement à genoux. Une analyse des logs, des slow queries, des paramètres vitaux de serveurs et une collaboration entre l’infogérant (nous) et la web agency a permis de mettre un nom sur le problème et de le corriger. Vicieux celui-ci.

Conception de Home

Bien concevoir sa home reste une clef du succès d’un site. La charge imposé par la Home sur l’ensemble de la charge serveur dépasse souvent les 40%, il est donc important de concevoir de manière optimale  cette page qui est le premier accueil qu’un client reçoit.

Pleinnnnn de produits

Eh oui ma bonne dame, plus y’en a, mieux c’est.

Faux. Lisez ce qu’en penses mes amis les pros comme Capitaine Commerce, François Ziserman ou Catherine Barba, assommer les clients sous 200 produits en homepage, ca n’apporte rien sinon un client perdu. Et plus on charge de produits, plus on fait travailler la base de données et les CPU pour interpréter le PHP et plus… ca rame.

Donc on a des clients perdus sur un site qui rame. Êtes vous bien persuadé que c’est  ce que vous voulez ???
(Press Y to continue if you are sure)

Dynamique, non mieux, random !

Bien tiens… J’ai une ligne de conduite précise, je sais ce que je vend et à qui. Aucun doute à ce sujet, j’ai profiler ma clientèle alors pour optimiser mes ventes, je charge mes produits en random…

Alors je veux bien que dans certains cas cela puisse avoir, à l’occasion, du sens mais clairement pas en home et pas tout le temps. Amazon, notre maitre à tous, ils envoient pas des produits en random à leurs clients. Ce qui a boosté leurs ventes et surtout le panier moyen de chaque acheteurs, c’est tout l’inverse, c’est l’envoie de produits ciblés.

Alors charger dynamiquement oui, dans certain cas pour s’adapter au client mais en random… ?

Car oui, le random et le dynamique sont des ennemis des caches, ces fameux caches (reverse proxy, celui de votre system de e-commerce, memcached, le Full Page  Cache et dans une moindre mesure celui des processeurs et des opcode cache de PHP) sont assez allergiques au hasard.

Et le statique ?

Vous y avez pensé ? Une landing statique bien faite, qui a la calculer chaque nuit en Cron, ca peut faire la différence. Sincèrement, afficher moins et mieux pour fournir à tout le monde une expérience utilisateur plus fluide, efficace et rapide, c’est une stratégie payante.

Plus votre site est véloce, plus et mieux il vend, c’est plus que démontré.

Inline URI

Alors celui-ci de tricks, il est soooo sexy.

Il faudrait tester en live la chose et étudier si c’est rentable mais le principe est marrant. En gros, dans votre CSS, plutot que de mettre la référence à une image externe, vous allez mettre en place une  chaine de caractère encodée en base64 :

url(data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7)

Ca donne un texte certe un peu chargé mais… Le Gzip est là pour nous aider. En gros le CSS va grossir, certes mais en contrepartie on peut le compresser en mod_gzip ou mod_deflate et finalement on n’a qu’une légère augmentation. Par contre, on économise autant de GET HTTP, ce qui n’est pas négligeable.

A vue de nez, je pense qu’il est valable de le faire pour les petites images, icones ou petits thumbnails. Il est possible aussi de faire un Sprite bien sûr, mais cette  technique alternative peut aussi avoir ses cotés sympas. Je dois avouer que c’est tout neuf pour moi alors je n’ai pas penssé à tous les points qui pourraient profiter des ces Data URIs.

(Beaucoup) plus d’infos sur cette technique ici : http://css-tricks.com/data-uris/

écrit par Philippe Humeau \\ tags: , , , , ,

jan 28

Le coup du mailing…

Alors voila…

Imaginons que la cellule marketing d’un client décide unilatéralement d’une super offre marketing. (ca n’arrive jamais rassurez vous, c’est dans un monde imaginaire)

Elle envoie un gros mailing pour soutenir le feu mais… Oublie de prévenir l’IT ou son hébergeur (pareil, c’est totalement utopique, toute ressemblance avec des faits réels serait fortuite). Forcément, le site monte dans les tours.

La solution

L’hébergeur et le DSI détecte le problème et se mettent d’accord, on lance trois machines en Cloud et là, le problème est résolu :) Merci Extend To Cloud.

Les ventes marche, le client est content, on va tous manger, satisfait de ce devoir accomplit.

Le vrai drame

Quand tout à coup… Entre en scène M. X et il appuie sur le bouton « Flush Magento cache », sans raison particulière, juste pour être sûr, parce que dans le doute, l’humain curieux explore tout son potentiel de liberté et que c’est aussi un peu cela le fameux « développement personnel », cliquez là où on veut, quand on veut !

Alors là, forcément, c’est pas la même…

Les serveurs ne disposent plus de leur cache, le drame arrive inexorablement. Une plateforme sans son cache chaud (hot cache) est 2 à 3 fois moins performante. Bilan, les utilisateurs en surfant vont petit à petit réchauffer le cache et générer les pages statiques mais ca demande de la ressource, le système rame.

Le drame « visuellement » parlant

Sur le Graph ci-dessous, lié au CPU de la machine qui sert la base de données, la barre nommée 1 montre le début du mailing et la barre nommée 2 montre le début du vidage de cache. (bien sur c’est un graph totalement hypothétique vous l’aurez compris)

Clairement, durant le mailing, on monte en charge mais ca tient bien. Dès que le bouton magique est pressé, la machine consomme 2 à 3 fois plus de CPU et se met à ramer.

La Conclusion

Si je ne l’ai pas dit cent fois, je ne l’ai jamais dit, mais informer, c’est aussi répéter :

  • On ne vide JAMAIS le cache en production sans raison
  • On ne vide JAMAIS le cache lors d’un pic de trafic type solde ou d’un mailing
  • On ne met jamais un nouveau site en production avant un pic (ce qui implique un vidage de cache)
  • Faire du développement personnel ne passe pas forcément par le fait de cliquer sur tous les boutons et particulièrement sur le bouton « Flush Cache »

D’une manière générale, avant d’appuyer sur le bouton magique qui provoque l’armaggedon, on en discute, on se pose la question de pourquoi on le fait, on vérifie si c’est indispensable, si c’est le seul moyen et dans le doute on en le fait pas.

Ce n’est pas une solution magique mais une solution de dernier recours. Un site en « cold cache » c’est atrocement lent pour les visiteurs et atrocement lourd pour les serveurs. J’ai même vu des setup ou les gens vident les caches en Cron toutes les heures, d’autres où sont lancé des réindexation de base de données plusieurs fois par jour…

Tout cela contribue à tuer les performances et là, pour le coup, Magento n’y est pour rien et n’y peut rien.

écrit par Philippe Humeau \\ tags: , , , , ,

août 28

Et les développeurs découvrirent la CRON…

Avec Magento et d’autres frameworks, il devient possible de faire exécuter au site une commande à heure/date/jour fixe par le mécanisme de Cron table. Ce mécanisme, très vieux (au moins 25 ans) et très stable est connu de tous les administrateurs systèmes et réseau, ses excès et débordements occasionnels (si l’on ne fait pas attention au contenu) aussi.

Sauf que quand les développeurs ont mis la mains sur ce petit outil d’automatisation, une nouvelle frontière s’est ouverte en terme de possibilité. Application d’un traitement sur tout le catalogue de nuit, système de calcul des réapprovisionnements, gestions de commandes ou des réductions etc…

Well, le principe est bon alors le partager doit être bon quelque part ?

Mais cela fait maintenant un moment qu’avec l’apparition de PHP, cette question revient :

« Vous pourriez passer la memory limit à 1, 2, 4 Go ? »
Non.

« Mais j’en ai besoin pour mes traitements »
Non.

« Non quoi ? »
Non je ne passerai pas la memory limit à 1,5 Go car vous n’en avez pas besoin.

Pourquoi ?

Déjà parce que l’on a pas besoin de 1 ou 2 ou 4 Go pour effectuer un traitement, aussi volumineux soit-il. Il est *presque* toujours possible de fragmenter le traitement en sous lots plus petits, d’allouer et désallouer sa RAM plus subtilement et d’une manière générale privilégier une méthode de travail moins RAM intensive. (écriture et stockage de résultats partiels, tableaux indexés, traitement par plus petit lots, utilisation de la gestion de mémoire du Zend framework etc…)

Que personne ne tente de s’abriter derrière le *presque*, le nombre des algorithmes complexes non factorisables ou fractionnables est connu et, dans leur très grande majorité, ils touchent aux traitements mathématiques, à la cryptographie ou aux problèmes dits « NP-complets ». Donc NON, il n’est pas impossible de programmer différemment un traitement PHP sur une collection de données, fussent elle grande.

D’ailleurs, la preuve, au final, le développeur contourne le problème et arrive à utiliser une memory limit raisonnable tout en résolvant son problème.

Et pourtant, elle tournait !

Ensuite 1 Go de RAM, c’est beaucoup. Au sens propre.

C’est à dire qu’à une époque pas si lointaine, on chargeait et traitait des collection de données 2 fois moins grandes mais également avec 10 fois moins de RAM. Le catalogue d’une société il y a 10 ans était peut être deux fois moins gros mais peut importe le système utilisé à l’époque, ca tournait et la RAM, à l’époque, il y en avait 10 fois moins et pourtant, ca tournait.

Le coté orgiaque de la progression du matériel et de ses coûts fausse le sens des réalités. Oui un cycle processeur ca compte. Oui une boucle mal optimisée ca joue, surtout multipliée par des milliers de visites. Oui 1 Go de RAM ce n’est pas rien. Selon la configuration de la machine, cela peut même représenter le quart de ses ressources mémoire…

De plus, la memory limit est posée pour tous les processus PHP, pas pour un en particulier. Résultat il est possible qu’un seul script soit gourmand mais rien ne nous certifie que cela ne sera pas le cas d’un autre. Et si 5 ou 6 processus PHP se mettent à consommer 1 Go de RAM, on arrive vite à des sommes qui peuvent mettre des serveurs à mal.

A une époque pas si lointaine sur Amiga et Atari ST, on optimisait jusqu’au moindre octet maintenant c’est une culture perdue, qu’on considère comme dépassée mais sincèrement, cet esprit était le bon. La société de l’hyper consommation nous pousse à manger plus, dépenser plus, imprimer plus et allouer plus de RAM. Ça va avec, le gâchis est devenu une culture. Pourquoi écrire 10 lignes de plus pour avoir une gestion plus rationnelle alors que comme cela ca marche ?

Sans compter que bon nombre de script n’exit jamais et reste en mémoire sans savoir quoi faire, à part bloquer 1 Go de RAM, pour rien.

Quelques bribes de solutions :

Fragmenter le traitement est le plus important, soit dans l’algorithme de traitement, soit dans la gestion de la mémoire.

Quand vous lisez un bouquin, vous le faite page après page et pas les 500 d’un coup, envisageons la même chose pour un serveur.

  1. Prenez la taille de votre traitement, diviser le par 64 ou 128 Mo et vous saurez le nombre de blocs à traiter, le nombre de processus qui devront s’exécuter à la suite pour venir à bout de la tâche. Une fois les résultats calculés, assemblez les au besoins.
  2. Traitez des tableaux ou des indexes qui référencent les données plutôt que toute la donnée en elle même, quand cela est possible.
  3. Utilisez des algorithmes et des clefs de hash pour sotcker et retrouver vos données.
  4. Traitez les données avec le langage le plus adapté. N’oubliez pas que PHP est 10 fois plus lent (au bas mot) que le C pour venir à bout d’un traitement. Sa gestion de la RAM est également moins efficace.
  5. Quand cela est possible, préférez un script SQL à un PHP qui fait du SQL, ca sera considérablement plus rapide et économe en ressources.
  6. Si vous continuer à faire vos Cron en PHP, utilisez Zend_Memory :
    Le composant Zend_Memory est destiné à gérer des données dans un environnement où la mémoire est limitée.
    Les objets mémoire (conteneurs de mémoire) sont produits par le manager de mémoire sur demande et mis en cache/chargés d’une manière transparente quand c’est nécessaire.

    (tiré de la doc ici : http://framework.zend.com/manual/fr/zend.memory.overview.html)
    ah… voila une solution élégante. J’utilise et si je dépasse la RAM allouer, ca swap sur le disque mes résultats intermédiaire.
    (Merci à Samuel Verdier de m’avoir soufflé la solution, il interviendra peut être prochainement sur ce blog pour nous donner des exemples concrets).

écrit par Philippe Humeau \\ tags: , , ,

juil 28

Un backoffice Magento lent à charger


Il existe deux ou trois cas différents au moins où le backoffice de Magento peut être très lent à charger. En 0.9.6 il manquait un index dans une table, en 1.1.6 il y avait un autre soucis et nous sommes tombés récemment sur un os en version 1.2, 1.3 et +.

Le bug est lié aux règles qui sont implémentées dans le catalogue. Avoir une règle spécifique , par exemple une réduction sur une catégorie, peut rendre le chargement du backoffice très lent. (horriblement lent en fait)

Rappelons en plus que le Flat Catalog, qui améliore les performances (d’environ 20% sur une 1.3), ne s’applique qu’au front, le backoffice lui est toujours obligé d’utiliser le modèle EAV.

D’habitude Wikigento ne touche que rarement au code sauf pour des raisons de performances ou de sécurité mais ici la nuance est assez fine vu qu’il s’agit bien d’optimiser les performances de Magento mais en patchant le code… Bref, on l’a donc on le diffuse !

Référence du Bug


NBS System a déclaré ce bug à Varien pour plusieurs de ses clients. Il est probable que d’autres magasins, hébergeurs, développeurs aient le problème, voici donc ce patch, en attendant que ceci soit intégré au code source de Magento (ce qui n’est pas le cas pour le moment)

Le bug est référencé sous le numéro et la description suivante chez Varien :
[#VQR-617032] : « Catalog price rules problem »

Il semble que ce patch améliore un peu les choses sans tout résoudre cependant.  (Nous réouvrirons le ticket si les performances ne sont pas  suffisantes)

Patcher son Magento


Attention, ce patch est conçu pour la version 1.2.1 de Magento.

Sur d’autres versions, vous aurez probablement à l’adapter. Plus précisément il est fait pour une version 0.13 de Mage_Weee (soit une révision N° 44593 des fichiers).

Il est assez simple à lire et à comprendre et donc à adapter. Cependant si vous l’adaptez pour une autre version ou si vous l’améliorez, vous devez le renvoyer à Varien (ou à moi, je le ferai parvenir à la bonne personne) puisque ce patch est en OSL 3. (Opensource Licence 3)

1°) Copiez le fichier sur le serveur (ftp ou scp) ou copier/coller le contenu de cette codebox dans un fichier :
cat > weee_discount_optimize_sm70_121.patch
CTRL+C sur la codebox puis boutonde droite de la souris dans un putty
CTRL+D dans le putty)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
Index: app/code/core/Mage/Weee/etc/config.xml
===================================================================
--- app/code/core/Mage/Weee/etc/config.xml	(revision 44593)
+++ app/code/core/Mage/Weee/etc/config.xml	(working copy)
@@ -28,7 +28,7 @@
 <config>
     <modules>
         <Mage_Weee>
-            <version>0.13</version>
+            <version>0.14</version>
         </Mage_Weee>
     </modules>
 
@@ -297,4 +297,4 @@
              </updates>
         </layout>
     </frontend>
-</config>
\ No newline at end of file
+</config>
Index: app/code/core/Mage/Weee/Model/Mysql4/Tax.php
===================================================================
--- app/code/core/Mage/Weee/Model/Mysql4/Tax.php	(revision 44593)
+++ app/code/core/Mage/Weee/Model/Mysql4/Tax.php	(working copy)
@@ -14,17 +14,44 @@
     {
         return $this->_getReadAdapter()->fetchCol($select);
     }
-
+
     public function updateDiscountPercents()
     {
-        $this->_getWriteAdapter()->delete($this->getTable('weee/discount'));
+		return $this->_updateDiscountPercents();
+    }
+
+    public function updateDiscountPercentsByPCondition($productCondition)
+    {
+    	return $this->_updateDiscountPercents($productCondition);
+    }
+
+    protected function _updateDiscountPercents($productCondition=null)
+    {
+        if (is_null($productCondition)) {
+            $this->_getWriteAdapter()->delete($this->getTable('weee/discount'));
+        } else {
+            $this->_getWriteAdapter()->delete($this->getTable('weee/discount'),
+                $this->_getReadAdapter()->quoteInto('entity_id in (?)',
+                    $this->_getReadAdapter()->fetchCol($productCondition->getIdsSelect($this->_getReadAdapter()))
+                )
+            );
+        }
+
         $now = strtotime(now());
 
         $select = $this->_getReadAdapter()->select();
-        $select->from(array('data'=>$this->getTable('catalogrule/rule_product')))
-            ->where('(from_time <= ? OR from_time = 0)', $now) -            ->where('(to_time >= ? OR to_time = 0)', $now)
-            ->order(array('data.website_id', 'data.customer_group_id', 'data.product_id', 'data.sort_order'));
+        $select->from(array('data'=>$this->getTable('catalogrule/rule_product')));
+
+        if (is_null($productCondition)) {
+            $select->where('(from_time <= ? OR from_time = 0)', $now); +            $select->where('(to_time >= ? OR to_time = 0)', $now);
+        } else {
+            $select->where('product_id in (?)',
+                $this->_getReadAdapter()->fetchCol($productCondition->getIdsSelect($this->_getReadAdapter()))
+            );
+        }
+
+        $select->order(array('data.website_id', 'data.customer_group_id', 'data.product_id', 'data.sort_order'));
 
         $data = $this->_getReadAdapter()->fetchAll($select);
         $productData = array();
@@ -68,4 +95,4 @@
 
         return $this->_getReadAdapter()->fetchOne($select);
     }
-}
\ No newline at end of file
+}
Index: app/code/core/Mage/Weee/Model/Observer.php
===================================================================
--- app/code/core/Mage/Weee/Model/Observer.php	(revision 44593)
+++ app/code/core/Mage/Weee/Model/Observer.php	(working copy)
@@ -195,7 +195,13 @@
 
     public function updateDiscountPercents(Varien_Event_Observer $observer)
     {
-        Mage::getModel('weee/tax')->updateDiscountPercents();
+    	if ( $observer->getEvent()->getProductCondition() ) {
+        	Mage::getModel('weee/tax')->updateDiscountPercentsByPCondition(
+        	   $observer->getEvent()->getProductCondition()
+        	);
+    	} else {
+    		Mage::getModel('weee/tax')->updateDiscountPercents();
+    	}
         return $this;
     }
 
@@ -252,4 +258,4 @@
 
         return $this;
     }
-}
\ No newline at end of file
+}
Index: app/code/core/Mage/Weee/Model/Tax.php
===================================================================
--- app/code/core/Mage/Weee/Model/Tax.php	(revision 44593)
+++ app/code/core/Mage/Weee/Model/Tax.php	(working copy)
@@ -152,6 +152,12 @@
         }
     }
 
+    public function updateDiscountPercentsByPCondition($productCondition)
+    {
+    	$this->getResource()->updateDiscountPercentsByPCondition($productCondition);
+    	return $this;
+    }
+
     public function updateDiscountPercents()
     {
         $this->getResource()->updateDiscountPercents();
Index: app/code/core/Mage/Weee/sql/weee_setup/mysql4-upgrade-0.13-0.14.php
===================================================================
--- app/code/core/Mage/Weee/sql/weee_setup/mysql4-upgrade-0.13-0.14.php	(revision 0)
+++ app/code/core/Mage/Weee/sql/weee_setup/mysql4-upgrade-0.13-0.14.php	(revision 0)
@@ -0,0 +1,31 @@
+<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category   Mage + * @package    Mage_Weee + * @copyright  Copyright (c) 2008 Irubin Consulting Inc. DBA Varien (http://www.varien.com) + * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0) + */ + +$installer = $this; +/* @var $installer Mage_Weee_Model_Mysql4_Setup */ + +$installer->getConnection()->modifyColumn($installer->getTable('weee/discount'), 'customer_group_id', 'SMALLINT(5) UNSIGNED DEFAULT NULL');
+$installer->getConnection()->modifyColumn($installer->getTable('weee/discount'), 'website_id', 'SMALLINT(5) UNSIGNED DEFAULT NULL');



2°) Loggez vous  sur le système en SSH

3°) Backupez votre fichiers
app/code/core/Mage/Weee/etc/config.xml
app/code/core/Mage/Weee/Model/Mysql4/Tax.php
app/code/core/Mage/Weee/Model/Observer.php
app/code/core/Mage/Weee/Model/Tax.php
app/code/core/Mage/Weee/sql/weee_setup/mysql4-upgrade-0.13-0.14.php

4°) Lancez la commande « patch p-0 < weee_discount_optimize_sm70_121.patch« 
5°) Priez
6°) Testez

if (patch == « good ») {Send(flower->Wikigento)} else {Send(insults->Varien)} endif

écrit par Philippe Humeau \\ tags: , , ,