« Aucun transporteur pouvant livrer à votre adresse » : la cause sur un vieux panier récupéré

par Luca Cavallini Cas d'assistance
« Aucun transporteur pouvant livrer à votre adresse » : la cause sur un vieux panier récupéré

Le symptôme

Un client rouvre un vieux panier, soit via un lien de récupération envoyé par un opérateur du back-office, soit depuis un e-mail de relance de panier abandonné, et arrive sans problème jusqu'à l'étape « Mode de livraison ». Là, il lit : « Il n'y a malheureusement aucun transporteur pouvant livrer à votre adresse. » Aucune autre erreur, aucun avertissement avant cette étape. Si le même client crée un tout nouveau panier avec exactement la même adresse, le checkout fonctionne et les transporteurs apparaissent immédiatement. Le panier concerné n'est généralement pas récent, il peut dater de plusieurs mois ou plusieurs années, et il vient d'être rouvert via un lien de récupération.

Ce que cela semblait être, et n'était pas

Le soupçon naturel, face à un message qui parle explicitement de l'adresse, est que l'adresse elle-même pose problème : supprimée, plus rattachée au client, ou simplement non couverte par une zone de livraison configurée. Aucune de ces trois pistes ne résiste à la vérification.

  • L'adresse du panier (au niveau de l'en-tête) est valide. Elle n'est pas supprimée, c'est l'adresse actuelle du client, et elle correspond à une zone géographique qui a des transporteurs actifs.
  • Des transporteurs existent et sont actifs pour cette zone. Vérifié manuellement depuis le back-office (Livraison -> Transporteurs) : plusieurs options sont configurées et actives pour cette zone, dont un transporteur payant et un retrait gratuit.
  • Le groupe du client a accès à ces transporteurs. Aucune restriction de groupe n'exclut le compte concerné.

Trois pistes raisonnables, toutes confirmées correctes, et l'erreur apparaissait quand même. À ce stade, la bonne question n'était plus « quels transporteurs existent pour cette adresse », mais « PrestaShop calcule-t-il réellement les transporteurs pour cette adresse, ou pour une autre ».

La vraie cause

Pour chaque panier, PrestaShop conserve deux références distinctes à une adresse de livraison : une au niveau de l'en-tête du panier (ps_cart.id_address_delivery), et une pour chaque ligne produit (ps_cart_product.id_address_delivery). Cette double structure existe pour gérer la livraison multiple, c'est-à-dire un seul panier avec des colis expédiés à des adresses différentes. Sur une boutique qui n'utilise pas la livraison multiple, les deux valeurs devraient toujours coïncider.

Le piège, c'est que PrestaShop ne met jamais à jour une adresse existante quand un client la modifie depuis son compte : il en crée une nouvelle et supprime logiquement l'ancienne (deleted = 1), en la gardant dans l'historique pour ne pas casser les commandes passées avec elle. Sur un panier actif, cela passe inaperçu : au passage suivant du client dans le checkout, l'en-tête du panier est mis à jour avec la nouvelle adresse. Mais si ce panier est abandonné avant la fin du checkout, la ligne produit enregistrée reste liée à l'ancien identifiant d'adresse, celui que le client supprime ensuite en la modifiant. L'en-tête peut ensuite être mis à jour de son côté (par exemple lors d'une visite ultérieure qui ne touche que l'adresse de facturation), ce qui laisse entre en-tête et ligne produit un décalage silencieux qu'aucun des deux ne signale.

La méthode qui calcule les options de livraison, Cart::getDeliveryOptionList(), regroupe les colis selon l'adresse enregistrée au niveau de la ligne produit, pas de l'en-tête : c'est exactement ainsi qu'elle gère correctement la livraison multiple quand elle est réellement utilisée. Avec une adresse de ligne supprimée, elle calcule quand même une liste de transporteurs (pour l'identifiant supprimé, qui existe toujours comme enregistrement, simplement marqué inactif), mais le checkout compare ensuite cette liste à l'adresse de l'en-tête, qui est différente. Aucune correspondance, aucun transporteur affiché, alors que des transporteurs pour l'adresse réelle existent et sont parfaitement valides.

Pourquoi cela touche surtout les vieux paniers : PrestaShop ne supprime jamais un panier abandonné, il reste indéfiniment dans la base de données, et un lien de récupération rouvre exactement le même enregistrement, avec exactement le même historique. Plus l'écart est grand entre la création d'un panier et sa récupération, plus il est probable que l'adresse enregistrée sur cette ligne ait été modifiée au moins une fois entre-temps.

Le correctif

Deux niveaux d'intervention distincts sont nécessaires : les paniers déjà cassés aujourd'hui, et ceux qui se casseront de la même façon à l'avenir.

Correction ponctuelle, pour les paniers déjà désynchronisés : une requête qui réaligne sur l'adresse de l'en-tête chaque ligne produit ayant une adresse supprimée, mais uniquement quand l'adresse de l'en-tête est valide et différente de celle de la ligne.

UPDATE ps_cart_product cp
 JOIN ps_cart c ON c.id_cart = cp.id_cart
 JOIN ps_address ap ON ap.id_address = cp.id_address_delivery
 JOIN ps_address ah ON ah.id_address = c.id_address_delivery
 SET cp.id_address_delivery = c.id_address_delivery
 WHERE cp.id_address_delivery <> 0
   AND ap.deleted = 1 AND ah.deleted = 0
   AND cp.id_address_delivery <> c.id_address_delivery;

Sur une table de paniers avec des années d'historique, cette requête peut toucher plusieurs centaines de lignes en un seul passage : dans le cas qui a fait apparaître ce problème, il s'agissait de 565 lignes, réparties sur 221 paniers différents.

Correction structurelle, pour les paniers futurs : un override de Cart::getDeliveryOptionList() qui effectue le même réalignement, mais uniquement pour le panier en cours d'ouverture, juste avant de calculer les options de livraison. En pratique, chaque vieux panier « se répare tout seul » au moment où il arrive au checkout, sans avoir besoin de balayer périodiquement toute la base de données.

Un détail mérite d'être dit explicitement : ce réalignement part du principe qu'un décalage entre l'adresse de la ligne et celle de l'en-tête est toujours une erreur à corriger, ce qui n'est vrai que si la boutique n'utilise pas la livraison multiple. Si la livraison multiple était un jour activée, des adresses différentes par ligne deviendraient légitimes, et ce correctif devrait être désactivé ou repensé : il casserait précisément le cas qu'il est censé gérer.

Une dernière catégorie a été volontairement laissée de côté : les paniers dont l'adresse de ligne et l'adresse d'en-tête sont toutes deux supprimées. Il ne reste aucune adresse valide sur laquelle réaligner, cette requête ne peut donc pas les corriger. Ce sont de vieux paniers qui n'ont jamais été rouverts ; s'ils le sont un jour, le parcours de checkout normal demandera de toute façon au client de choisir ou de confirmer une adresse valide avant de continuer, ils se règlent donc d'eux-mêmes au moment où ils sont réellement utilisés.

Comment vérifier que le correctif tient

  • Rouvrez un panier présentant le décalage connu (ou reproduisez-en un : une adresse de ligne supprimée, un en-tête sur une adresse valide) et vérifiez que l'étape de livraison affiche les transporteurs attendus, et non le message d'erreur.
  • Après la correction ponctuelle, recomptez combien de lignes ont encore une adresse de ligne supprimée et différente de celle de l'en-tête : le résultat doit revenir à zéro.
  • Vérifiez dans le code que l'override est bien celui qui est chargé (get_class() sur l'instance de Cart pendant le checkout, ou un contrôle method_exists), et pas seulement que le fichier existe sur le serveur : un override peut être présent et inactif si le cache des classes n'a pas été régénéré.
  • Répétez la vérification périodiquement si la boutique récupère beaucoup de vieux paniers via des campagnes e-mail ou de remarketing : c'est exactement là que ce problème réapparaît le plus, parce que c'est exactement le type de panier qui accumule ce décalage avec le temps.

La boutique sur laquelle ce cas a été diagnostiqué reste volontairement anonyme. Si un panier PrestaShop récupéré affiche « aucun transporteur disponible » alors qu'un nouveau panier avec la même adresse fonctionne, le bon endroit où chercher n'est pas la configuration des transporteurs : c'est de savoir si l'adresse enregistrée sur la ligne produit et celle enregistrée sur l'en-tête du panier sont réellement le même enregistrement. Pour la maintenance courante d'une boutique PrestaShop, y compris ce genre de cas, un résumé des services se trouve sur cette page.

Laisser un commentaire

Les commentaires sont modérés avant publication.

← Blog

Chargement...
Retour en haut