Le développement d’une communication automatisée entre WooCommerce et le service logistique Cubyn

EDIT 19/03/2018 : Cubyn a depuis mis en place un plugin WooCommerce qui s’occupe de tout ça directement. Vous pourrez le trouver à cette adresse.

 

Cubyn est un service qui propose une gestion logistique complète des commandes d’un site e-commerce. Envoyez la liste des commandes à l’application, et un coursier passera prendre les produits concernés à l’heure souhaitée. Cubyn se charge ensuite de les emballer puis de les expédier aux clients.

L’envoi de commandes à ce service peut se faire via un fichier Excel téléchargeable depuis l’application et déjà mis en forme. Cette méthode peut cependant vite s’avérer laborieuse pour un commerce à forte affluence. Il est alors intéressant d’automatiser ce processus en envoyant une commande à l’application dès le paiement effectué, puis en alertant le client de l’évolution de l’expédition.

Bien qu’en pleine expansion, Cubyn est un service encore jeune, et il n’existe pas encore de plugins ou d’extensions dédiées aux plateformes e-commerce les plus populaires. Heureusement, Cubyn fournit une API qui va nous permettre de réaliser nos tâches d’automatisation.

L’envoi automatique d’une commande après paiement

Une commande va être représentée dans l’application par un parcel (paquet / colis). La première étape est donc l’analyse de la structure de données attendue par Cubyn pour la création du parcel.

API : Création de parcels

La création du parcel

L’API attend des données formatées en JSON. Nous allons donc commencer par créer un tableau PHP contenant l’ensemble des informations nécessaires à la création du parcel avant de le convertir dans le format demandé.

La documentation de l’API nous informe que seule l’adresse du destinataire de la commande est nécessaire à la création du parcel. Ne vous y fiez pas, cette documentation à plusieurs lacunes et il est préférable d’apporter le maximum d’informations dont vous disposez. Les informations manquantes à la création seront explicitées dans la réponse du serveur.

La création du parcel est souhaitée après le paiement d’une commande, nous allons donc nous servir de l’action WooCommerce ‘woocommerce_payment_complete’. Cette action nous fournit l’ID de la commande en paramètre, ce qui nous permet de récupérer toutes les informations utiles.

function build_parcel( $order_id ) {

	// Récupération des informations de la commande
	$order = wc_get_order( $order_id );

	/*
		La création de notre parcel se fera ici
	 */

	return $order_id;
}
add_action( 'woocommerce_payment_complete', 'build_parcel', 10, 1 );

Passons maintenant à la création du tableau de notre parcel. La documentation contient tous les paramètres utilisables, nous allons commencer par les plus complexes.

L’adresse

L’adresse est considérée comme un objet dans la structure JSON demandée par Cubyn. Cela se traduit par un tableau PHP qu’il faudra ajouter au tableau formant le parcel.

Nous commençons par créer le tableau de l’adresse, puis nous lui ajoutons ses champs grâce aux informations extraites de la commande. Une fois l’adresse complète, nous ajoutons ce tableau au parcel.

// Le tableau du parcel
$parcel = array();

/* L'adresse */
$address = array();

$address['line1'] = $order->shipping_address_1;
$address['line2'] = $order->shipping_address_2;
$address['zip'] = $order->shipping_postcode;
$address['city'] = $order->shipping_city;
$address['state'] = $order->shipping_state;
$address['country'] = $order->shipping_country;
$address['additionalInformation'] = $order->customer_message;

// Ajout de l'adresse au parcel
$parcel['address'] = $address;

Les produits

Les produits sont également inclus dans un tableau. C’est ici un peu plus complexe car il nous faut boucler afin de récupérer l’ensemble des produits d’une commande. Le procédé est ensuite le même, nous ajoutons ce tableau de produits au parcel.

/* Les produits */
$items = array();

foreach ( $order->get_items() as $item ) {

	$item_details = array();
	
	$item_details['name'] = $item['name'];
	$item_details['count'] = $item['qty'];
	$item_details['reference'] = $item['product_id'];
	$item_details['value'] = $item['line_total'];

	// Ajout du produit en cours au tableau de produits
	array_push( $items, $item_details );

}

// Ajout des produits au parcel
$parcel['items'] = $items;

Il peut être nécessaire pour votre client que le nom du produit contienne davantage d’informations, ce sera notamment le cas s’il s’agit de produits variables, dont la couleur ou encore la taille peut différer. Dans ce cas, il vous suffit de récupérer les informations souhaitées et de les concaténer avec le nom du produit.

Le mode de livraison

Cubyn accepte trois modes de livraison, colissimo, express ou relay. Si ces noms de coïncident pas avec les ID de vos modes de livraisons créés dans l’interface d’administration de WooCommerce, il faut faire une condition afin d’envoyer le nom correct à Cubyn.

/* Le mode de livraison */
$shipping_methods = $order->get_shipping_methods();

foreach ( $shipping_methods as $method ) {

	if ( $method['method_id'] === 'flat_rate' ) {
		$parcel['deliveryMode'] = 'express';
	} else {
		$parcel['deliveryMode'] = 'colissimo';
	}

}

Les autres paramètres

Le reste des informations ne nécessite pas de traitement particulier, il est donc possible de les ajouter directement au parcel.

/* Les autres paramètres */
$parcel['firstName'] = $order->shipping_first_name;
$parcel['lastName'] = $order->shipping_last_name;
$parcel['organizationName'] = $order->shipping_company;
$parcel['phone'] = $order->billing_phone;
$parcel['email'] = $order->billing_email;
$parcel['value'] = $order->get_total();
$parcel['orderRef'] = $order_id;

La conversion au format JSON

Notre tableau PHP complet, il nous faut maintenant le convertir au format JSON attendu par l’API. Pour cela, rien de plus simple, PHP le fait automatiquement avec la fonction json_encode.

/* Le formattage en JSON */
$parcel_encoded = json_encode( $parcel );

Il nous reste maintenant à envoyer ces données à Cubyn pour que la magie opère. Nous allons effectuer cet envoi dans une fonction différente nommée ‘send_parcel’, qui prend en paramètre la chaîne de caractère obtenue après l’encodage et représentant le parcel au format JSON.

Voici le code complet jusqu’à présent.

function build_parcel( $order_id ) {

        // Récupération des informations de la commande
	$order = wc_get_order( $order_id );

	// Le tableau du parcel
	$parcel = array();

	/* L'adresse */
	$address = array();

	$address['line1'] = $order->shipping_address_1;
	$address['line2'] = $order->shipping_address_2;
	$address['zip'] = $order->shipping_postcode;
	$address['city'] = $order->shipping_city;
	$address['state'] = $order->shipping_state;
	$address['country'] = $order->shipping_country;
	$address['additionalInformation'] = $order->customer_message;

	$parcel['address'] = $address;

	/* Les produits */
	$items = array();

	foreach ( $order->get_items() as $item ) {

		$item_details = array();
		
		$item_details['name'] = $item['name'];
		$item_details['count'] = $item['qty'];
		$item_details['reference'] = $item['product_id'];
		$item_details['value'] = $item['line_total'];

		// Ajout du produit en cours au tableau de produits
		array_push( $items, $item_details );

	}

	$parcel['items'] = $items;

	/* Le mode de livraison */
	$shipping_methods = $order->get_shipping_methods();

	foreach ( $shipping_methods as $method ) {

		if ( $method['method_id'] === 'flat_rate' ) {
			$parcel['deliveryMode'] = 'express';
		} else {
			$parcel['deliveryMode'] = 'colissimo';
		}

	}

	/* Les autres paramètres */
	$parcel['firstName'] = $order->shipping_first_name;
	$parcel['lastName'] = $order->shipping_last_name;
	$parcel['organizationName'] = $order->shipping_company;
	$parcel['phone'] = $order->billing_phone;
	$parcel['email'] = $order->billing_email;
	$parcel['value'] = $order->get_total();
	$parcel['orderRef'] = $order_id;

	/* Le formattage en JSON */
	$parcel_encoded = json_encode( $parcel );

	/* L'appel de la fonction d'envoi */
	send_parcel( $parcel_encoded );

	return $order_id;
}
add_action( 'woocommerce_payment_complete', 'build_parcel', 10, 1 );

function send_parcel( $parcel ) {

	/*
		L'envoi de notre parcel se fera ici
	 */
}

L’envoi du parcel avec l’HTTP API de WordPress

Les exemples d’envoi de la documentation sont réalisés avec cURL. Vous pouvez utiliser la méthode que vous souhaitez, mais il est préférable au sein de l’environnement WordPress d’utiliser l’HTTP API, conçue afin d’être compatible sur la totalité des serveurs. De plus, vous remarquerez très vite que la syntaxe est très simplifiée.

La récupération de la clé API

Nous récupérons tout d’abord la clé API de notre compte Cubyn qui nous donne l’autorisation d’utiliser cette API. Chez El Tigre, nous aimons utiliser le plugin Advanced Custom Fields afin de créer facilement une interface d’administration personnalisée. Nous récupérons ainsi dans cet exemple la clé entrée au préalable, via un champ créé avec ACF, dans une page d’options du Back-Office.

$api_key = get_field( 'cubyn_api_key', 'option' );

L’envoi de la requête POST

L’ajout du parcel s’effectue avec une requête POST, nous allons du utiliser la fonction wp_remote_post. Nous passons à cette fonction deux paramètres, l’URL de l’API de Cubyn ainsi que les arguments permettant le transfert du contenu, à savoir notre parcel et les headers attendus.

Nous utilisons ici l’adresse de l’API de ‘production’, mais sachez qu’il est préférable d’effectuer tous vos tests au préalable avec un compte Sandbox qu’il est possible de demander aux équipes de Cubyn.

$url = 'https://api.cubyn.com/v1/parcels';

$args = array(
	'headers' => array( 
		'X-Application' => $api_key,
		'Content-Type'  => 'application/json'
	),
	'body' 	  => $parcel
);

$response = wp_remote_post( $url, $args );

L’ajout de l’ID du parcel dans la commande WooCommerce

L’ajout effectué avec succès, Cubyn vous renvoie en tant que réponse l’ID du parcel. Il est important de conserver cet ID car il vous permettra de mettre à jour un parcel ou encore de le supprimer.

Nous allons conserver cet ID dans la commande WooCommerce, ce qui nous permettra de le retrouver via l’ID de cette dernière et donc à travers les différents hook utilisés. Il faut d’abord remettre au bon format cette réponse. Puis nous l’ajoutons dans les informations de la commande.

$response = wp_remote_post( $url, $args );

// Mise en forme de la réponse
$response_decoded = json_decode( $response['body'] );

// Ajout de l'ID du parcel dans la commande WooCommerce
update_post_meta( $order_id, '_parcel_id', $response_decoded->id );

Nous voilà donc avec un envoi automatisé de chaque commande passée avec WooCommerce à Cubyn. Bien sûr, des conditions doivent être ajoutées à ce code pour éviter de travailler avec des mauvaises données et attraper les erreurs. Nous avons choisi ici de les omettre par soucis de clarté du code.

Voici le code complet de la fonction d’envoi.

function send_parcel( $parcel ) {

	$api_key = get_field( 'cubyn_api_key', 'option' );
	$url = 'https://api.cubyn.com/v1/parcels';
	$args = array(
		'headers' => array( 
			'X-Application' => $api_key,
			'Content-Type'  => 'application/json'
		),
		'body' 	  => $parcel
	);

	$response = wp_remote_post( $url, $args );

	// Mise en forme de la réponse
	$response_decoded = json_decode( $response['body'] );

	// Ajout de l'ID du parcel dans la commande WooCommerce
	update_post_meta( $order_id, '_parcel_id', $response_decoded->id );

}

La suppression d’une commande de Cubyn

Au même titre que l’ajout de parcels, il est également intéressant que la suppression se fasse automatiquement.

Pour ce faire, nous utilisons le hook ‘woocommerce_order_status_cancelled’ qui est appelé à chaque annulation de commande. L’ID de cette dernière nous est encore une fois fourni par l’action.

L’API attend dans l’URL l’ID du parcel que nous avons au préalable enregistré dans la commande WooCommerce.
Il faut ici utiliser une méthode DELETE, cela est possible via la fonction wp_remote_request dans laquelle nous précisons la méthode utilisée.

Voici le code de la fonction complète.

function delete_parcel( $order_id ) {

	$api_key = get_field( 'cubyn_api_key', 'option' );
	$parcel_id = get_post_meta( $order_id, '_parcel_id' );
	$url = 'https://api.cubyn.com/v1/parcels/' . $parcel_id[0];
	$args = array(
		'headers' => array( 
			'X-Application' => $api_key
		),
		'method' => 'DELETE'
	);

	wp_remote_request( $url, $args );
}
add_action( 'woocommerce_order_status_cancelled', 'ly_delete_parcel', 10, 1 );

Il s’agira d’utiliser la même fonction si vous souhaiter mettre à jour un parcel, cette fois-ci avec la méthode PUT.

L’utilisation des webhooks

Cubyn propose des webhooks permettant de notifier un de vos script lorsque l’une des trois actions suivantes à lieu :

• Un parcel est supprimé
• Un parcel est envoyé
• Le statut d’un parcel évolue lors de son transit

Nous allons utiliser ces webhooks d’une part pour envoyer au client un lien lui permettant de suivre son colis, et d’autre part pour mettre le statut terminé dans l’interface d’administration à une commande livrée.

API : Notification via les webhooks

La réception des données JSON

Cubyn fait parvenir les informations de l’événement et du parcel concerné sous format JSON. Il faut tout d’abord commencer par décoder ces données afin de les exploiter en PHP.

Pour récupérer ces données, vous ne pouvez pas directement utiliser la variable $_POST, celle-ci sera vide car Cubyn envoie une requête avec un header ‘application/json’. La lecture des données se fera donc avec la fonction file_get_contents qui ira récupérer les données brutes. Ces données peuvent ensuite être décodées avec la façon habituelle.

$data = json_decode( file_get_contents( 'php://input' ) );

La sécurisation du script

Afin que n’importe qui ne puisse pas utiliser votre script, il est important d’en sécuriser l’accès. Cubyn préconise d’une part de leur fournir une adresse HTTPS, et d’autre part de tester si la clé API envoyée par le webhook correspond bien à la clé de notre compte.

if ( $api_key != $data['key'] ) {
	header("HTTP/1.0 401 Unauthorized");
	exit;
}

L’envoi d’un email de suivi de l’expédition

Cubyn propose une page de suivi qui permet, avec l’ID du parcel, de suivre la progression du colis. Nous souhaitons transmettre ce lien aux clients lorsqu’un colis est entre les mains du transporteur.

Pour ce faire, nous récupérons tout d’abord les informations de la commande WooCommerce grâce à son ID renvoyé par le wekbook.
Nous écoutons ensuite l’événement reçu. Si celui-ci est parcel:picked, nous envoyons un email au client contenant le lien de la page de suivi correspondant à son colis.

if ( $data['event'] == 'parcel:picked' ) {

	// Construction de l'URL de suivi
	$tracking_url = 'http://track.cubyn.com/' . $data['parcel']['id'];
	// Récupération de l'email du client
	$to = $order->billing_email;
	$subject = "Commande expédiée";
	// Récupération du modèle d'email auquel nous avons transmis l'URL de suivi
	$message = file_get_contents( 'email-template.php?tracking=' . $tracking_url );
	$headers[] = 'Content-type: text/html; charset=UTF-8';
	$headers[] = 'From: Votre boutique <boutique@ecommerce.fr>';

	wp_mail( $to, $subject, $message, $headers );

}

Le changement de statut d’une commande lors de sa livraison

Pour terminer le processus, il faut passer le statut de la commande en commande terminée dans l’interface d’administration de WooCommerce lorsque la livraison a été effectuée.

Nous écoutons cette fois-ci l’événement ‘parcel:carrier-status:changed’ avec le statut ‘CARRIER_DELIVERED’. Lorsque nous le recevons, nous mettons à jour le statut de la commande correspondante.

if ( $data['event'] == 'parcel:carrier-status:changed' && $data['parcel']['status'] == 'CARRIER_DELIVERED' ) {

	$order->update_status( 'completed' );

}

Vous avez accès à davantage de statuts, la liste est disponible dans la documentation. Voici le code complet de notre exemple de script de réception des webhooks.

$api_key = get_field( 'cubyn_api_key', 'option' );
$data = json_decode( file_get_contents( 'php://input' ), true );

if ( $api_key != $data['key'] ) {
	header("HTTP/1.0 401 Unauthorized");
	exit;
}

$order = wc_get_order( $data['parcel']['orderRef'] );

if ( $data['event'] == 'parcel:carrier-status:changed' && $data['parcel']['status'] == 'CARRIER_DELIVERED' ) {

	$order->update_status( 'completed' );

} else if ( $data['event'] == 'parcel:picked' ) {

	// Construction de l'URL de suivi
	$tracking_url = 'http://track.cubyn.com/' . $data['parcel']['id'];
	// Récupération de l'email du client
	$to = $order->billing_email;
	$subject = "Commande expédiée";
	// Récupération du modèle d'email auquel nous avons transmis l'URL de suivi
	$message = file_get_contents( 'email-template.php?tracking=' . $tracking_url );
	$headers[] = 'Content-type: text/html; charset=UTF-8';
	$headers[] = 'From: Votre boutique <boutique@ecommerce.fr>';

	wp_mail( $to, $subject, $message, $headers );

}

5 thoughts on “Le développement d’une communication automatisée entre WooCommerce et le service logistique Cubyn

  1. Bonsoir et merci beaucoup pour cet article. Je suis en train d’intégrer Cubyn à mon site e-commerce et j’ai une question concernant les modes de livraison. Comment trouver les ID de nos modes de livraisons ? Dans votre exemple vous parlez du mode « flat_rate ». Personnellement j’ai besoin d’avoir 3 modes de livraison : standard, express et relay. J’ai créé ces dernières à partir du mode « Forfait » mais je ne sais pas comment récupérer les infos (ID) pour faire correspondre mes modes de livraison avec le « deliveryMode » de Cubyn. Exemple : if ( $method[‘method_id’] === ‘Livraison en point Relais’ ) { $parcel[‘deliveryMode’] = ‘relay’; }.
    Merci pour votre aide.

    1. Bonjour Cyril,

      Effectivement cette partie mériterait de plus amples précisions.
      « flat_rate » est l’ID correspondant justement à la méthode de livraison « Forfait »,
      présente par défaut dans WooCommerce.

      Pour connaître rapidement les IDs de toutes les méthodes de livraison
      enregistrées, indépendamment de votre version de WooCommerce,
      voici un morceau de code très simple qui affichera, pour chaque méthode,
      son nom puis son ID:


      global $woocommerce;
      $shipping_methods = $woocommerce->shipping->load_shipping_methods();
      foreach ( $shipping_methods as $method ) {
      echo $method->method_title . ' / ' . $method->id . '
      ';
      }

      Vous pouvez ensuite adapter vos conditions.

  2. Bonjour Clément et merci pour votre réponse. J’ai actuellement 3 modes de livraison (standard, express et relay) mais j’utilise la même méthode (flat_rate). Devrais-je en utiliser une autre pour les modes express et relay ? Dans tous les cas l’ID correspondant est similaire pour mes 3 modes et je ne sais pas comment différencier mes modes de livraison pour leur attribuer un deliveryMode. Voici ce que je souhaite faire :
    foreach ( $shipping_methods as $method ) {
    if ($method[‘method_id’] === ‘ID_flat_rate_colissimo’) {
    $parcel[‘deliveryMode’] = ‘colissimo’;
    } elseif ($method[‘method_id’] === ‘ID_flat_rate_express’) {
    $parcel[‘deliveryMode’] = ‘express’;
    } elseif ($method[‘method_id’] === ‘ID_flat_rate_relay’) {
    $parcel[‘deliveryMode’] = ‘relay’;
    }
    }

    Merci pour votre aide.

    1. Vous devez effectivement créer différentes méthodes de livraison distinctes.
      WooCommerce fournit un tuto officiel pour utiliser sa Shipping Method API et créer celles que vous souhaitez.
      https://docs.woocommerce.com/document/shipping-method-api/
      Dans ce cas, vous définirez vous-même l’ID et vous pourrez les différencier facilement.

      Un autre tuto plus complet sur la Shipping Method API est disponible sur tutsplus.
      https://code.tutsplus.com/tutorials/create-a-custom-shipping-method-for-woocommerce–cms-26098

Répondre à Cyril Annuler la réponse

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *