Petit retour sur un bug que j’ai traqué ces derniers jours dans Droit de Rétractation for WooCommerce (DRW) — le genre de bug silencieux, qui ne plante rien, n’affiche aucune erreur, mais qui laisse une donnée fausse en base sans que personne ne s’en aperçoive tout de suite. C’est exactement le genre de chose qui m’obsède un peu trop, mais c’est aussi pour ça que ce plugin existe.
Le problème
DRW gère tout le cycle de vie d’une demande de rétractation : réception, acceptation, remboursement, clôture. Pour le remboursement, le plugin propose son propre bouton dans l’écran de gestion des demandes, qui déclenche refund_items() et met tout à jour proprement.
Sauf que dans la vraie vie, un e-commerçant qui gère un retour ne pense pas forcément « je dois aller dans l’écran DRW pour rembourser ce client ». Il ouvre la commande WooCommerce, comme il le fait pour n’importe quel remboursement, et clique sur « Rembourser » depuis l’interface native. C’est un réflexe totalement légitime — c’est l’écran qu’il connaît, celui qu’il utilise tous les jours pour toutes ses commandes, rétractation ou non.
Et c’est là que ça coinçait : le remboursement se faisait bien côté WooCommerce, l’argent partait bien vers le client, mais la demande de rétractation, elle, restait figée sur son statut précédent dans DRW. Aucune erreur visible, juste une donnée qui ne se met pas à jour.
Pourquoi c’est plus vicieux qu’il n’y paraît
Mon premier réflexe a été d’ajouter un hook sur l’action native de remboursement WooCommerce (sync_native_refund()), pour que DRW soit informé dès qu’un remboursement est créé ailleurs que par son propre bouton. Logique, simple, ça aurait dû suffire.
Sauf qu’en testant en conditions réelles, j’ai découvert deux angles morts distincts, empilés l’un sur l’autre :
Premier angle mort : associer le bon remboursement à la bonne ligne de commande. Une commande peut contenir plusieurs articles, chacun avec potentiellement sa propre demande de rétractation. Il fallait donc que la synchronisation retrouve précisément quel article de la commande correspondait à quelle ligne de remboursement — pas juste « un remboursement a eu lieu sur cette commande », mais « sur quel article exactement ».
Second angle mort, plus subtil : le remboursement lui-même n’était pas traité comme une décision. Dans DRW, une demande de rétractation passe par un statut de décision (en attente, acceptée, refusée) avant même de parler de remboursement. Si un article était encore « en attente d’examen » au moment où le marchand faisait son remboursement natif, mon code recalculait bien le montant remboursé — mais le calcul du statut global, lui, continuait de se baser sur la décision (pending), en ignorant complètement le fait qu’un remboursement venait d’avoir lieu. Résultat : la demande restait bloquée sur « en attente », alors que le client avait déjà été remboursé.
La correction : un remboursement effectif vaut acceptation implicite. Si le marchand rembourse un article encore en attente, c’est que sa décision est prise — de facto. Le code marque désormais l’article comme accepté avant de recalculer le statut global, ce qui débloque la synchronisation dans tous les cas de figure.
Comment on a confirmé que c’était réglé
Debug logging temporaire à chaque point de sortie de la fonction, tests rejoués sur mon environnement DDEV avec les deux scénarios qui posaient problème :
- une demande encore en attente, remboursée directement depuis WooCommerce ;
- une demande déjà acceptée manuellement, remboursée ensuite depuis WooCommerce (sans repasser par le bouton DRW).
Les deux scénarios remontent maintenant correctement le statut « remboursée » dans l’écran DRW, avec la ligne de journal qui trace bien que la synchronisation s’est faite automatiquement.
Pourquoi j’en parle
Ce genre de décalage entre « ce que fait un plugin spécialisé » et « ce que fait réellement un marchand au quotidien dans WooCommerce » est, je pense, assez répandu dans les extensions de gestion de rétractation — l’écran natif de remboursement est un point d’entrée tellement évident qu’il est facile de l’oublier en se concentrant sur son propre flux dédié. Pour DRW, c’était l’occasion de fermer complètement cet écart, dans les deux sens (peu importe où et comment le remboursement est initié, le statut de la demande reste fiable).
Si vous gérez des retours et rétractations sur WooCommerce et que vous avez déjà eu ce genre de statut qui ne « colle pas » avec la réalité de votre commande, ça vaut le coup d’y regarder de près — chez DRW ou ailleurs.

