Passa al contenuto principale

Costruire un flusso di integrazione tra Akeneo PIM e PrestaShop

1. Introduzione

Questo documento spiega come trasferire i dati prodotto da Akeneo PIM a PrestaShop usando la piattaforma di integrazione Flowlyze. Poiché su Flowlyze non esiste un nodo di destinazione nativo per PrestaShop, l'integrazione viene realizzata con una richiesta HTTP personalizzata. Il flusso alimenta direttamente un ambiente PrestaShop, automatizzando completamente la gestione del catalogo prodotti.

Video tutorial

💡 Suggerimento: Guarda il video qui sotto per vedere il flusso passo passo.

2. Prerequisiti

  • Un account Akeneo PIM attivo con accesso alle API.
  • Un'installazione PrestaShop accessibile via HTTP.
  • Una Webservice Key generata dal pannello di amministrazione di PrestaShop (necessaria per la Basic Auth).
  • Un file image_proxy.php posizionato nella directory root di PrestaShop per gestire le operazioni di download/upload.
  • Un account Flowlyze attivo.
  • Conoscenza intermedia di C# per la formattazione dei dati e la costruzione dell'XML.

3. Architettura dell'integrazione

Per aggirare i colli di bottiglia di performance e i limiti della sandbox C#, il flusso dati avviene nelle seguenti fasi:

  • Trigger: Flowlyze si connette ad Akeneo e recupera i dati grezzi dei prodotti.
  • Mapping: I dati grezzi di Akeneo vengono mappati sui campi core di PrestaShop usando il nodo Mapping di Flowlyze.
  • Trasformazione e creazione prodotto (controller C#): Lo script C# elabora i dati JSON, costruisce il payload XML e lo invia a PrestaShop. Il prodotto viene salvato nel database (senza immagini).
  • Destinazione HTTP: Poiché non esiste un adapter nativo per PrestaShop, il prodotto viene inviato con una destinazione HTTP.
  • Trasferimento immagini (PHP Proxy): Lo script C# estrae il nuovo Product ID dalla risposta HTTP 201 di successo. Invia questo ID e i codici degli asset immagine di Akeneo come payload JSON al file image_proxy.php. Il file PHP scarica le immagini e le carica sull'API PrestaShop.

4. Implementazione passo passo

Passo 4.1: Configurare il trigger su Akeneo PIM

Per prima cosa, stabilisci una connessione sicura alla sorgente dati:

  1. Nell'area di lavoro di Flowlyze, aggiungi un nuovo nodo Source e seleziona Akeneo.
  2. Autentica la connessione con le credenziali API di Akeneo (Client ID, Secret, Username, Password).
  3. Definisci quali cataloghi prodotto recuperare e la frequenza del trigger (schedulata o manuale).

Passo 4.2: Trasformazione e mapping dei dati (Flowlyze)

La struttura dati accettata da PrestaShop è più specifica rispetto ad altre piattaforme, quindi il passo di formattazione è cruciale:

  1. Mapping Action: Mappa i campi base in arrivo da Akeneo sui campi richiesti da PrestaShop (ad esempio codice riferimento, ID categoria principale).
  2. Data Formatting Action: Utilizza l'ambiente C# di Flowlyze per rendere i dati in ingresso pienamente compatibili con l'API PrestaShop. Usa lo script C# per pulire e preparare strutture dati nidificate come i campi multilingua o le regole fiscali.
// 1. MAPPATURA CATEGORIE
System.Collections.Generic.Dictionary<string, string> categoryMap = new System.Collections.Generic.Dictionary<string, string>(System.StringComparer.OrdinalIgnoreCase)
{
{ "3d_printers", "10" },
{ "robotics", "11" },
{ "drones", "12" },
{ "industrial_tools", "13" }
};

var reference = Data.GetString("reference") ?? "DEFAULT-REF";
var nameValue = Data.GetString("name") ?? "Default Product Name";
var weight = Data.GetString("weight") ?? "0.0000";
var price = Data.GetString("price") ?? "0.00";

string idCategory = "2";
var categoryList = Data.GetListString("categories");
if (categoryList != null && categoryList.Count > 0)
{
foreach (var rawCategory in categoryList)
{
if (string.IsNullOrWhiteSpace(rawCategory)) continue;
foreach (var cat in categoryMap)
{
if (rawCategory.IndexOf(cat.Key, System.StringComparison.OrdinalIgnoreCase) >= 0)
{
idCategory = cat.Value;
break;
}
}
if (idCategory != "2") break;
}
}

var activeVal = Data.Get("active");
bool isActive = activeVal != null && System.Convert.ToBoolean(activeVal);
string activeStr = isActive ? "1" : "0";

string linkRewrite = nameValue.ToLower()
.Replace(" ", "-").Replace("ş", "s").Replace("ı", "i").Replace("ğ", "g")
.Replace("ö", "o").Replace("ç", "c").Replace("ü", "u").Replace("---", "-").Replace("--", "-");

// 2. CREAZIONE DEL TEMPLATE XML PRESTASHOP
string xmlOutput = $@"
<prestashop xmlns:xlink=""http://www.w3.org/1999/xlink"">
<product>
<id_category_default><![CDATA[{idCategory}]]></id_category_default>
<reference><![CDATA[{reference}]]></reference>
<price><![CDATA[{price}]]></price>
<weight><![CDATA[{weight}]]></weight>
<active><![CDATA[{activeStr}]]></active>
<state><![CDATA[1]]></state>
<name>
<language id=""1""><![CDATA[{nameValue}]]></language>
<language id=""2""><![CDATA[{nameValue}]]></language>
</name>
<link_rewrite>
<language id=""1""><![CDATA[{linkRewrite}]]></language>
<language id=""2""><![CDATA[{linkRewrite}]]></language>
</link_rewrite>
</product>
</prestashop>";

// 3. INVIO DEL PRODOTTO A PRESTASHOP TRAMITE HTTP REQUEST
var request = new CustomHttpRequest
{
Url = "{{prestashopURL}}/api/products",
Method = "POST",
Headers = new System.Collections.Generic.Dictionary<string, string>
{
{ "Content-Type", "application/xml" }
},
Body = new System.Text.StringBuilder(xmlOutput)
};

string apiKey = "{{Your_apiKey}}";
var authValue = System.Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes($"{apiKey}:"));
request.Headers.Add("Authorization", "Basic " + authValue);

var response = Http.Execute(request);

if (response.Status >= 200 && response.Status < 300)
{
// 4. ESTRAZIONE DELL'ID PRODOTTO
string productId = "";
int startIdx = response.Body.IndexOf("<id><![CDATA[");
if (startIdx != -1)
{
startIdx += 13;
int endIdx = response.Body.IndexOf("]]></id>", startIdx);
if (endIdx != -1)
{
productId = response.Body.Substring(startIdx, endIdx - startIdx);
}
}

// 5. INVIO MASSIVO DEI CODICI IMMAGINE AL PHP PROXY (passo di accelerazione)
var imagesRaw = Data.GetListString("images");
if (!string.IsNullOrEmpty(productId) && imagesRaw != null && imagesRaw.Count > 0)
{
var validAssets = new System.Collections.Generic.List<string>();
foreach (var code in imagesRaw)
{
if (!string.IsNullOrWhiteSpace(code)) validAssets.Add(code);
}

if (validAssets.Count > 0)
{
string assetJson = "[\"" + string.Join("\",\"", validAssets) + "\"]";
string proxyUrl = "{{prestashopURL}}/image_proxy.php";
string jsonPayload = $"{{\"product_id\": \"{productId}\", \"assets\": {assetJson}}}";

var proxyRequest = new CustomHttpRequest
{
Url = proxyUrl,
Method = "POST",
Headers = new System.Collections.Generic.Dictionary<string, string>
{
{ "Content-Type", "application/json" }
},
Body = new System.Text.StringBuilder(jsonPayload)
};

var proxyResponse = Http.Execute(proxyRequest);
Logger.Log($"Operazione immagini via proxy - HTTP {proxyResponse.Status}: {proxyResponse.Body}");
}
}

return Return.Skip($"Operazione riuscita (HTTP {response.Status}): prodotto creato, elaborazione immagini eseguita lato proxy.");
}
else
{
return Return.Error($"Errore PrestaShop (HTTP {response.Status}): {response.Body}");
}

Passo 4.3: Configurare l'action su PrestaShop

Poiché non esiste un nodo nativo, è necessario configurare manualmente l'operazione con un nodo HTTP Request:

  1. Autenticazione (Auth Config): Aggiungi un HTTP Request come nodo di destinazione. Imposta Auth Type su Basic Auth. Incolla la Webservice Key ottenuta da PrestaShop nel campo Username. Configura il campo password in base ai requisiti di sicurezza.
  2. Impostazioni di base (Settings): Inserisci l'URL di PrestaShop ({{prestashopURL}}) nel campo Base URL.
  3. Endpoint e metodo: Imposta il Resource Path su /api/products per la risorsa specifica. Poiché stiamo creando un nuovo prodotto, seleziona POST come Method.
  4. Comportamento della richiesta: Seleziona la casella Send one request per message per garantire che ogni prodotto venga elaborato singolarmente e senza errori.
  5. Upload immagini (Proxy): Una volta creato il prodotto con successo, estrai il nuovo ID prodotto con C# e invialo insieme ai riferimenti delle immagini all'endpoint image_proxy.php. Questo file proxy trasferisce le immagini a PrestaShop come multipart/form-data all'interno del server.
<?php
$data = json_decode(file_get_contents('php://input'), true);

if (!isset($data['assets']) || !isset($data['product_id'])) {
http_response_code(400);
die(json_encode(["status" => "error", "message" => "Parametri mancanti"]));
}

$productId = $data['product_id'];
$assets = $data['assets'];
$prestaApiKey = '{{Your_apiKey}}';

$akeneoDomain = "{{Your_akeneoDomain}}";
$clientId = "{{Your_clientId}}";
$clientSecret = "{{Your_clientSecret}}";
$username = "{{Your_username}}";
$password = "{{Your_password}}";

// Ottieni il token Akeneo
$chToken = curl_init("$akeneoDomain/api/oauth/v1/token");
curl_setopt($chToken, CURLOPT_POST, true);
curl_setopt($chToken, CURLOPT_POSTFIELDS, http_build_query([
'grant_type' => 'password',
'username' => $username,
'password' => $password,
'client_id' => $clientId,
'client_secret' => $clientSecret
]));
curl_setopt($chToken, CURLOPT_RETURNTRANSFER, true);
$tokenRes = curl_exec($chToken);
curl_close($chToken);

$tokenData = json_decode($tokenRes, true);
$token = $tokenData['access_token'] ?? null;

if (!$token) {
http_response_code(500);
die(json_encode(["status" => "error", "message" => "Impossibile ottenere il token Akeneo.", "response" => $tokenRes]));
}

$results = [];
$tempPath = tempnam(sys_get_temp_dir(), 'img') . '.jpg';

foreach ($assets as $assetCode) {
if (empty($assetCode)) continue;

$chAsset = curl_init("$akeneoDomain/api/rest/v1/asset-families/imported_assets/assets/$assetCode");
curl_setopt($chAsset, CURLOPT_HTTPHEADER, ["Authorization: Bearer $token", "Accept: application/json"]);
curl_setopt($chAsset, CURLOPT_RETURNTRANSFER, true);
$assetRes = curl_exec($chAsset);
$assetStatus = curl_getinfo($chAsset, CURLINFO_HTTP_CODE);
curl_close($chAsset);

$assetData = json_decode($assetRes, true);
$mediaLink = $assetData['values']['media_link'][0]['data'] ?? null;

if (!$mediaLink) {
$results[] = "$assetCode saltato: link non recuperato da Akeneo (HTTP $assetStatus).";
continue;
}

$chImg = curl_init($mediaLink);
$fp = fopen($tempPath, 'wb');
curl_setopt($chImg, CURLOPT_FILE, $fp);
curl_setopt($chImg, CURLOPT_HEADER, 0);
curl_setopt($chImg, CURLOPT_HTTPHEADER, ["Authorization: Bearer $token"]);
curl_exec($chImg);
curl_close($chImg);

if (filesize($tempPath) > 0) {
// Carica su PrestaShop (URL e autenticazione aggiornati)
$uploadUrl = "{{prestashopURL}}/api/images/products/$productId?ws_key=$prestaApiKey";
$chUpload = curl_init($uploadUrl);

curl_setopt($chUpload, CURLOPT_POST, true);
$cFile = curl_file_create($tempPath, 'image/jpeg', 'image.jpg');
curl_setopt($chUpload, CURLOPT_POSTFIELDS, ['image' => $cFile]);
curl_setopt($chUpload, CURLOPT_RETURNTRANSFER, true);
curl_setopt($chUpload, CURLOPT_FOLLOWLOCATION, true);

$upRes = curl_exec($chUpload);
$upStatus = curl_getinfo($chUpload, CURLINFO_HTTP_CODE);
curl_close($chUpload);

if ($upStatus >= 200 && $upStatus < 300) {
$results[] = "$assetCode aggiunto.";
} else {
$results[] = "$assetCode errore: PrestaShop ha restituito HTTP $upStatus. Dettaglio: $upRes";
}
} else {
$results[] = "$assetCode errore: il file è stato scaricato a 0 KB.";
}
}

if (file_exists($tempPath)) unlink($tempPath);
echo json_encode(["status" => "success", "details" => $results]);
?>

5. Test e pubblicazione

Per verificare il flusso HTTP personalizzato:

  1. Avvia un'esecuzione di test in Flowlyze usando il payload di un singolo prodotto da Akeneo.
  2. Controlla i log della Execution History di Flowlyze per assicurarti che i passi di Mapping, Formatting e HTTP POST siano stati completati senza errori.
  3. Se i log indicano un esito positivo, attiva il flusso in produzione. Una volta che il flusso è live, accedi al pannello di amministrazione di PrestaShop e verifica manualmente che i prodotti siano stati aggiunti con la categoria, lo SKU e i prezzi corretti.

6. Gestione errori e troubleshooting

  • Problemi di connessione: Verifica che il Base URL configurato in Flowlyze corrisponda all'URL corretto di PrestaShop ({{prestashopURL}}).
  • Errori di autenticazione (401 Unauthorized): Verifica che la Webservice Key in Basic Auth abbia i permessi necessari per l'operazione POST (scrittura) nel pannello PrestaShop.
  • Incongruenze di formato (400 Bad Request): L'HTTP Request dialoga direttamente con l'API e non tollera errori strutturali. Controlla l'output generato dal codice C# per assicurarti che i campi obbligatori di PrestaShop (ad esempio gli ID lingua mancanti) non siano omessi.

7. Conclusioni e prossimi passi

Senza bisogno di un nodo di integrazione nativo, hai costruito un ponte dati completamente automatizzato tra Akeneo e PrestaShop usando le capacità HTTP Request di Flowlyze. Come passo successivo, puoi arricchire la pipeline senza codice aggiuntivo integrando uno step di notifica (ad esempio Slack o Email) per ricevere avvisi automatici ogni volta che una sincronizzazione prodotto viene completata o se si verifica un errore.