# Xero ou QuickBooks depuis WooCommerce : synchroniser la facturation

> Pousser automatiquement les commandes validées d'une boutique WooCommerce vers un logiciel comptable tiers, sans dupliquer ni perdre une seule écriture.

- Auteur : WordPress Développement
- Publié le : 2024-10-14
- Mis à jour le : 2024-10-14
- Catégorie : Extensions
- URL : https://www.wpmoderne.fr/extensions/xero-quickbooks-woocommerce-synchroniser-facturation/

## L’essentiel

- Le statut de commande déclenche l'envoi, pas un CRON périodique
- Un identifiant externe stocké évite tout doublon en cas de rejeu
- Les deux API exigent une authentification OAuth2 renouvelée

`wc_get_order( $order_id )->get_status()` : c'est ce simple appel, placé au bon endroit dans le cycle de vie d'une commande WooCommerce, qui détermine si une facture part correctement vers la comptabilité ou reste bloquée dans les limbes. Sur un projet e-commerce dont le client changeait de logiciel comptable — de Xero vers QuickBooks — sans vouloir modifier son processus de facturation, la question posée était de construire une seule interface d'envoi capable de basculer entre les deux API sans réécrire toute la logique métier.

La génération de factures PDF locales, déjà en place et fonctionnelle sur ce projet, ne fait pas partie de ce chantier : il s'agit uniquement de pousser les données de commande validées vers le logiciel comptable choisi, pour que la comptabilité générale du client dispose des écritures sans ressaisie manuelle.

## Choisir le déclencheur : le changement de statut, pas une tâche planifiée

Une tâche CRON qui parcourt périodiquement les commandes récentes pour les synchroniser fonctionne, mais introduit un délai variable et complique la gestion des doublons. Une approche plus directe consiste à s'accrocher au changement de statut de commande, via le hook `woocommerce_order_status_changed`, qui se déclenche précisément au passage vers un statut facturable :

```
add_action( 'woocommerce_order_status_changed', function( $order_id, $old_status, $new_status ) {
    if ( 'processing' !== $new_status && 'completed' !== $new_status ) {
        return;
    }
    if ( get_post_meta( $order_id, '_accounting_synced', true ) ) {
        return;
    }
    accounting_sync_queue_order( $order_id );
}, 10, 3 );
```

## Une interface commune, deux implémentations distinctes

> L'essentiel à retenir : Le statut de commande déclenche l'envoi, pas un CRON périodique ; Un identifiant externe stocké évite tout doublon en cas de rejeu ; Les deux API exigent une authentification OAuth2 renouvelée

Xero et QuickBooks exposent chacun une API REST authentifiée par OAuth2, mais avec des structures de données différentes pour représenter une facture et un client. Plutôt que de dupliquer la logique métier, l'extension définit une interface PHP commune que chaque connecteur implémente séparément :

- Une interface `Accounting_Connector` avec deux méthodes : `push_invoice( Order_Data $data )` et `find_or_create_contact( $customer_email )`.
- Une classe `Xero_Connector` qui traduit les données de commande vers le format attendu par l'API Xero, avec ses codes de compte comptable.
- Une classe `QuickBooks_Connector` qui fait de même pour le format QuickBooks, structurellement différent malgré un objectif identique.
- Le code métier (déclenchement, file d'attente, gestion des doublons) reste strictement identique quel que soit le connecteur actif, sélectionné via un réglage d'administration.

## Éviter les doublons en cas de rejeu

Un appel réseau vers Xero ou QuickBooks peut échouer après avoir partiellement réussi côté serveur distant — la facture est créée, mais la réponse de confirmation se perd en chemin, par exemple sur un délai d'attente réseau. Sans précaution, un rejeu automatique recrée alors une deuxième facture identique côté logiciel comptable, une erreur qui perturbe directement le rapprochement bancaire du client. La parade consiste à stocker systématiquement, dès la première tentative, un identifiant de tentative unique généré côté WordPress, transmis dans un champ de référence externe accepté par les deux API, puis à vérifier son existence avant tout renvoi :

```
$reference = 'wc-' . $order_id . '-' . wp_generate_uuid4();
update_post_meta( $order_id, '_accounting_attempt_ref', $reference );
// La référence est incluse dans la requête d'envoi et revérifiée
// avant tout nouvel essai, via une recherche par référence externe.
```

## Le renouvellement du jeton, un détail qui casse tout s'il est oublié

Les deux API reposent sur OAuth2 avec un jeton d'accès de courte durée et un jeton de renouvellement de plus longue durée. Sans mécanisme de renouvellement automatique, la synchronisation cesse silencieusement de fonctionner dès l'expiration du premier jeton, souvent plusieurs jours après la mise en production, ce qui rend le diagnostic plus difficile qu'une panne immédiate. Une tâche planifiée via Action Scheduler, indépendante du flux de facturation, vérifie et renouvelle le jeton avant son expiration plutôt qu'après.

> Sur ce projet, le conseil qui a le plus servi ensuite : ne jamais coder un connecteur comptable comme un cas particulier isolé. Définir l'interface commune dès le premier connecteur, même s'il n'y en a qu'un au départ, évite une réécriture complète au moment où le client change de logiciel.

## Pour aller plus loin

Cette architecture à interface commune et connecteurs interchangeables tient la route au-delà de la seule comptabilité : elle s'applique aussi bien à un changement de transporteur logistique qu'à un changement de plateforme d'emailing. Le vrai investissement se situe dans la définition initiale de l'interface, pas dans le code de chaque connecteur pris isolément, qui reste généralement simple une fois la structure commune posée.
