07
mars 2019

PIM Akeneo, importer des images dans Excel en VBA

PIM Akeneo, importer des images dans Excel en VBA

Je teste actuellement la mise en place d’un PIM pour gérer notre bibliothèque de médias et les informations produits. L’idée est de centraliser l’information et la rendre accessible au plus grand nombre au travers d’un navigateur mais aussi pour d’autres applications. Dans cet article je vous expliquerais comment procéder pour récupérer ces informations depuis Excel en utilisant l’API d’Akeneo et Flyimg-Akeneo.

Je pars principe que vous savez ce qu’est un PIM, que vous connaissez la solution proposé par Akeneo, que vous connaissez Docker.

Je remercie l’équipe d’Akeneo qui m’a orienté sur les bonnes pistes et je précise que je ne suis pas un expert en VBA.

Pré-requis

  • Une instance Akeneo fonctionnelle comportant un catalogue avec quelques produits;
  • La possibilité de créer un container Docker pour Flyimg et Traefik activé (marche sans mais vous devrez exposer/mapper le port 80 de votre container);
  • Excel avec quelques librairies que nous ajouterons plus tard.

Activer l’API

Connectez-vous en tant qu’administrateur ou bien avec un compte ayant les droits administrateurs. Allez sur la page Système > Connexions API. Créer une autorisation spécifique pour VBA, ensuite attribuez à un groupe dédié afin de gérer les habilitations. Pour mes tests j’ai utilisé le compte administrateur.

Création de la clé pour l'API Akeneo

Création du container Flyimg-Akeneo

Flyimg-Akeneo est un fork de Flyimg dont le rôle est de générer à la demande la déclinaison d’une image source. Il est possible de redimensionner l’image, la faire pivoter, « croper » l’image et bien d’autres choses que je vous laisse découvrir sur le site de Flyimg (https://github.com/flyimg).

Connectez-vous à votre serveur Docker et télécharger la dernière version sur le dépôt Github (https://github.com/opengento/flyimg-akeneo).

Modifier le fichier config/parameters.yml

akeneo_api:
  base_url: "http://192.168.xxx.xxx"
  client_id: "1_xxxxx"
  client_secret: "1xxxx"
  user: "admin"
  password: "admin"

base_url : correspond à votre serveur Akeneo
client_id et client_secret correspond aux valeurs que vous avez généré sur la page Système > Connexions API d’Akeneo.
user et password correspond à l’utilisateur faisant partie du groupe autorisé à utiliser cette clé d’API.

Construisez votre image avec la commande

docker build –t flyimg-akeneo --label flyimg-akeneo

Créer votre container avec les labels permettant à Traefik de faire le mappage de port vers le 80. Connectez vous en shell à votre container et lancez la commande

composer install

FlyImg va s’installer en quelques minutes. Une fois fini lancez votre navigateur et essayez de vous connecter à votre container. Si tout se passe bien vous arrivez à une page sur fond gris.

Page par défaut de FlyImg

Excel et VBA

Avant d’aller plus loin vous allez avoir besoin du module VBA-Json disponible ici (https://github.com/VBA-tools/VBA-JSON). Dans l’éditeur VBA ajoutez ce module à votre projet et activez la référence « Microsoft Scripting Runtime ».

Commencé par créer un UserForm que vous nommerez : FmOptionsImportImage sur lequel vous ajouterez :

  • Une liste déroulante nommée : LsTaille;
  • Trois champs texte nommés : TxtLigneRecherche, TxtColonneRecherche, TxtColonneImage;
  • Deux boutons : BtValide et BtAnnuler.

Double cliquez sur le bouton « BtValide » et collez ce code

' Quitte le programme
Private Sub BtAnnuler_Click()
  Unload Me
End Sub

' Appel de la procédure d'import
Private Sub BtValide_Click()
  ' Appel de la procédure d'import
  Call getRoot(LigRech, ColRech, ColAct)
End Sub

' Charge la liste déroulante
Private Sub UserForm_Activate()
  FmOptionsImportImage.LsTaille.AddItem ("50 px")
  FmOptionsImportImage.LsTaille.AddItem ("60 px")
  FmOptionsImportImage.LsTaille.AddItem ("70 px")
  FmOptionsImportImage.LsTaille.AddItem ("80 px")
  FmOptionsImportImage.LsTaille.AddItem ("100 px")
  FmOptionsImportImage.LsTaille.AddItem ("110 px")
  FmOptionsImportImage.LsTaille.AddItem ("120 px")
  FmOptionsImportImage.LsTaille.AddItem ("150 px")
End Sub

Créer un module nommez “importImage” et collez tout ce code

'Option Explicit
Public Product, Token As Object
Public strUrl, ColRech, ColAct As String
Public LigRech, CellHeight, imgWidth As Integer

' Encode client_id et secret en base64
' ne marche pas pour le moment
Function EncodeBase64(text As String) As String
  Dim arrData() As Byte
  arrData = StrConv(text, vbFromUnicode)

  Dim objXML As MSXML2.DOMDocument
  Dim objNode As MSXML2.IXMLDOMElement

  Set objXML = New MSXML2.DOMDocument
  Set objNode = objXML.createElement("b64")

  objNode.DataType = "bin.base64"
  objNode.nodeTypedValue = arrData
  EncodeBase64 = objNode.text

  Set objNode = Nothing
  Set objXML = Nothing
End Function

' Connexion et création du token Akeneo
Sub ConnectAuth()
    Dim objRequest, scriptControl As Object
    Dim client_id, secret As String
    
    client_id = "1_xxxx"
    secret = "1xxxx"
    strUrl = "http://192.168.xxx.xxxx"
    
    Set scriptControl = CreateObject("MSScriptControl.ScriptControl")
    scriptControl.Language = "JScript"

    Set objRequest = CreateObject("MSXML2.XMLHTTP")
    With objRequest
        .Open "POST", strUrl & "/api/oauth/v1/token", False
        .SetRequestHeader "Content-Type", "application/x-www-form-urlencoded"
        ' ToDo : ne marche pas en générant à la volée le base64 ?
        .SetRequestHeader "Authorization", "Basic EncodeBase64"
        .Send "grant_type=password&username=admin&password=admin"
        
        Set Token = scriptControl.Eval("(" & .responseText & ")")
    End With
End Sub

' Stockage de la largeur de l'image
' et conserve la plus grande
Sub upWidth(imgNewWidth)
    If (imgNewWidth > imgWidth) Then
        imgWidth = imgNewWidth
    End If
End Sub

' Gestion des erreurs json
Sub getError(Code, Message)
    Dim pErreur As String
    
    pErreur = CStr(Code)
    If (pErreur = 404) Then
        MsgBox ("Erreur " & Code & " : " & Message)
    Else
        MsgBox ("Erreur inconnue")
    End If
End Sub

' Récupération de l'objet Product
' Itmref : sku du produit à chercher
Sub getProduct(Itmref)
    Dim objRequest As Object
    Set objRequest = CreateObject("MSXML2.XMLHTTP")
    
    With objRequest
        .Open "GET", strUrl & "/api/rest/v1/products/" & Itmref, False
        .SetRequestHeader "Content-Type", "application/json"
        .SetRequestHeader "Authorization", "Bearer " & Token.access_token
        .Send
        
        Set Product = JsonConverter.ParseJson(.responseText)
    End With
End Sub

' Transformation de l'image akeneo par
' flyimg-akeneo
Sub getPicture(ImgHeight)
    If (Product("values").Exists("img_0")) Then   ‘ Changer img_0 par le nom du champ qui représente l’image que vous voulez insérer
        Set img = ActiveSheet.Pictures.Insert("http://AdresseDuServeurFlyImg/upload/st_1,h_" & ImgHeight & "/" & Product("values")("img_0")(1)("data"))
        img.Top = ActiveCell.Top + 2
        img.Left = ActiveCell.Left + 2
        img.Placement = 2
        img.PrintObject = 1
        
        ' Mise à jour de la largeur de la cellule
        Call upWidth(img.Width)
    End If
End Sub

Sub getRoot(LigRech, ColRech, ColAct)
    Dim ImgHeight As Integer
    imgWidth = 0
    
    ' Dimension de la cellule
    ' hauteur de cellule
    ' 50 -> 50 px
    ' 60 -> 60 px
    ' 70 -> 70 px
    ' 81 -> 80 px
    ' 100 -> 100 px
    ' 110 -> 110 px
    ' 120 -> 120 px
    ' 150 -> 150 px
    
    ' Largeur de la celulle
    ' 9 -> 50 px
    ' 11 -> 60 px
    ' 13 -> 70 px
    ' 15 -> 80 px
    ' 19 -> 100 px
    ' 21 -> 110 px
    ' 23 -> 120 px
    ' 28 -> 150 px
    Select Case FmOptionsImportImage.LsTaille.List(FmOptionsImportImage.LsTaille.ListIndex)
        Case "50 px" To "50 px"
            CellHeight = 50 ' hauteur de cellule
            ImgHeight = 50
            'ImgWidth = 50
            
        Case "60 px" To "60 px"
            CellHeight = 60 ' hauteur de cellule
            ImgHeight = 60
            'ImgWidth = 60
            
        Case "70 px" To "70 px"
            CellHeight = 70 ' hauteur de cellule
            ImgHeight = 70
            'ImgWidth = 70
            
        Case "80 px" To "80 px"
            CellHeight = 80 ' hauteur de cellule
            ImgHeight = 80
            'ImgWidth = 80
            
        Case "100 px" To "100 px"
            CellHeight = 100 ' hauteur de cellule
            ImgHeight = 100
            'ImgWidth = 100
            
        Case "110 px" To "110 px"
            CellHeight = 110 ' hauteur de cellule
            ImgHeight = 110
            'ImgWidth = 110
            
        Case "120 px" To "120 px"
            CellHeight = 120 ' hauteur de cellule
            ImgHeight = 120
            'ImgWidth = 120
            
        Case "150 px" To "150 px"
            CellHeight = 150 ' hauteur de cellule
            ImgHeight = 150
            'ImgWidth = 150
            
        Case "" To ""
            MsgBox ("Vous devez choisir une taille d'images")
    End Select

    ' Ligne à laquelle commencer la recherche
    If LigRech = 0 Then
        LigRech = FmOptionsImportImage.TxtLigneRecherche.Value
        If LigRech = "" Then Exit Sub
    End If
    
    ' Colonne de recherche.
    If ColRech = "" Then
        ColRech = FmOptionsImportImage.TxtColonneRecherche.Value
        If ColRech = "" Then Exit Sub
    End If

    ' Colonne d'affichage
    If ColAct = "" Then
        ColAct = FmOptionsImportImage.TxtColonneImage.Value
        If ColAct = "" Then Exit Sub
    End If

    ' Connexion et récupération du Token
    Call ConnectAuth

    Range(ColRech & LigRech).Select
    For i = 1 To Range("A" & "65535").End(xlUp).Row
        If (Range(ColRech & i).Value <> "") Then
            ' Récupération des informations produit
            Call getProduct(Range(ColRech & i).Value)
            
            If (CStr(Product.Exists("code"))) Then
                Call getError(Product("code"), Product("message"))
            Else
                Range(ColAct & i).Select
                ActiveCell.EntireRow.RowHeight = CellHeight
                Call getPicture(ImgHeight)
            End If
        End If
    Next i
    
    ' Ajuste la largeur de la colonne avec
    ' la largeur de l'image la plus grande
    ' 4.75 permet la convertion de pixel à points... en gros
    ActiveCell.EntireColumn.ColumnWidth = (imgWidth / 4.75) + 0.5
    
    FmOptionsImportImage.BtValide.Visible = False
    FmOptionsImportImage.BtAnnuler.Caption = "Quitter"
End Sub

Avant de lancer le programme vous devez modifier dans la fonction ConnectAuth() les variables client_id, secret, strUrl.

Normalement le programme est censé réaliser l'encodage en base64 automatiquement mais pour une raison que je ne connais pas cela ne marche pas (encore), du coups vous allez devoir le faire à la main. Allez sur le site https://www.base64decode.org/ copier/coller les valeurs client_id et secret mais attention sous cette forme

client_id:secret

ne pas oublier le : de séparateur. Ensuite coller le résultat dans la fonction ConnectAuth à la ligne

.SetRequestHeader "Authorization", "Basic VotreEncodageBase64"

Dans la fonction getPicture l'adresse de votre serveur FlyImg est à modifier et le nom du champ contenant le chemin d'accès à l'image (dans mon cas img_0)

    If (Product("values").Exists("img_0")) Then
    [...]
    Set img = ActiveSheet.Pictures.Insert("http://AdresseDuServeurFlyImg/upload/st_1,h_" & ImgHeight & "/" & Product("values")("img_0")(1)("data"))

Test

Dans votre projet VBA, sur la Feuil1, dans la colonne de votre choix saisissez un sku par ligne et lancez le programme en lancant la feuille FmOptionsImportImage. Renseignez les valeurs de taille et dans quelle colonne mettre les images et cliquez sur le bouton "Insérer".

Si tout ce passe bien les images devraient être insérée sur la ligne correspondante au sku et au dimenssion que vous avez séléctionné.

Evolution

Dans le cas où il y a plusieurs images disponible, ouvrir une fenêtre pour permettre à l'utilisateur de sélectionner l'image qu'il souhaite importer.

Administrateur système de métier mais surtout curieux de découvrir de nouvelles technos très orientées DIY. A mes heures perdues je fais de la photo avec toujours une petite envie d'intégrer des DIY sous forme de timelaps à base de raspberry.

1 commentaire

Sandra a dit

Excellent article sur la récupération des informations d'Excel à l'aide des API Akeneo et Flyimg-Akeneo. Merci d'avoir partagé. Article bien expliqué et organisé.

Répondre

Écrire un commentaire

Quelle est la première lettre du mot zqkz ? :

PIM Akeneo, importer des images dans Excel en VBA - Philippe Maladjian - Péripéties bucoliques d'un administrateur systèmes au royaume de la virtualisation, du stockage et accessoirement photographe à ses heures perdues