Post-vente
Avoirs et remboursements
Émettre un avoir plutôt que supprimer une facture, et les deux mécaniques de remboursement (Ponto, MangoPay).
Avoirs & remboursements
Quand une vente capote après facturation (lot endommagé, litige, annulation), on ne supprime jamais une facture : on émet un avoir (credit note) et, si l'acheteur avait payé, on le rembourse.
💡 Pourquoi ne pas juste supprimer la facture ?Parce que c'est illégal : une facture émise est un document comptable définitif, numéroté sans trou. La seule façon de la « défaire » est d'émettre le document inverse — l'avoir — qui annule tout ou partie du montant. La numérotation garde la trace des deux (
2026-R000xxx pour les avoirs plateforme, NC26xxxxxx côté vendeur).L'avoir (CREDIT_NOTE)
- Créé comme une facture normale mais avec
docType = CREDIT_NOTEet des montants négatifs (forcés par le calcul) ; - Rattaché à sa facture parente par le même
invoiceGroup(la parente = la facture non-avoir du groupe) ; - Peut être partiel (on annule 200 € sur 1 000 €) ou total ;
- Workflow court :
TO_VALIDATE → INVOICED → EXECUTED/SUBMITTED → SETTLED.
Le remboursement : deux mécaniques selon le circuit
Action REIMBURSE sur la facture payée :
- Contrôle : montant remboursé ≤ montant payé (
REIMBURSE_AMOUNT_HIGHER_THAN_PAIDsinon) ; - Création immédiate d'un mouvement bancaire
OUT(statutSUBMITTED) vers l'IBAN du client ; - Mise à jour de la facture :
amountPaiddiminue,amountDueremonte ; si remboursement total → facture et itemREIMBURSED; - Le virement part avec le prochain lot de paiements (fichier Isabel).
Le remboursement passe par la validation d'un avoir sur la facture payée (parente en statut PAID ou CONFIRMED) :
- On retrouve le PayIn d'origine de l'acheteur ;
- Si facturation double et que l'argent est déjà parti chez le vendeur : on inverse d'abord le transfer vendeur (transfer refund : l'argent revient du wallet vendeur vers le wallet acheteur) ;
- Puis refund du PayIn : carte → remboursement direct sur la carte ; le webhook
PAYIN_REFUND_SUCCEEDEDsolde le mouvement et l'avoir ; - En échec (
PAYIN_REFUND_FAILED) : mouvementREJECTED, traitement manuel back-office.
⚠️ Limites MangoPay à connaître
- Le refund d'un PayIn carte n'est possible que ~11 mois ; au-delà de 13 mois la transaction est archivée (introuvable → refund impossible, traitement manuel).
- Le refund d'un PayIn par virement n'est pas supporté par l'API : le remboursement doit passer par un payout vers le compte d'origine (chantier identifié, voir
PLAN-US-reversement-acheteur.md/ tickets RA20-2198 & RA20-5541). - Deux refunds partiels du même montant doivent être espacés de 24 h (anti-doublon MangoPay).
Ponto :
book-keeper/src/services/bankMovements/movementReimburse.js ; MangoPay : book-keeper/src/services/bankMovements/movementCreditNoteMangopay.js (statuts parents remboursables, recherche du payin d'origine, détection double facturation isDoubleInvoicingSale, création des mouvements de refund) ; workflow : performReimburse() dans jobs/src/helpers/invoiceWorkflow.js ; audit : table mangopay_refunds.Et les frais d'annulation ?
Si l'annulation est imputable à l'acheteur (non-paiement, non-enlèvement), le contrat peut prévoir des frais d'annulation facturés via une facture de service : BUYER_CANCELLATION_FEES_NOT_PAID (n'a pas payé), BUYER_CANCELLATION_FEES_NO_PICK_UP (n'est pas venu enlever), ou côté vendeur SELLER_CANCELLATION_FEES (retrait du lot après adjudication).