---
suivi: 1960
date: 2026-10-16
sujet: Diagnostic refus Sage — modification d’une facture électronique
chantier: factures-electroniques / comptabilisation
type: diagnostic
statut: poussé
hash: 0ff1bc49f
fichiers:
  - docs/suivi/SUIVI_1960_diag_refus_modification_fe_sage.md
---

# SUIVI #1960 — diagnostic : Sage refuse de modifier la facture électronique 2660201

## PROMPT ENVOYÉ

PHASE 1 diagnostic. Dépôt 2541, RECORDNO 2660201, entité E-04. Après #1953 le XML a LINE_NO 1 et VENDORID par ligne. Relecture juste avant l’envoi : STATE Draft, ligne 1 = 58,26, ligne 3 = taxe 0 avec PARENTENTRY = ligne 1. Comptabiliser le 16/10 à 14:38:02 : Sage refuse « Les factures électroniques qui ne sont pas à l'état de brouillon ou non refusées ne peuvent pas être modifiées, supprimées ou extournées. » (IntacctService.php:1951). Quel champ, quelle valeur, que peut-on encore faire, le flux #1853 est-il viable, le statut a-t-il bougé depuis le refus « Fournisseurdimension » du matin, combien d’autres FE sont dans le même état. Proposition PHASE 2, sans coder. Aucun envoi Sage, aucun second bill, aucune écriture en base. Fiche sur main.

## Fiches lues

- #1853 LEÇON : la comptabilisation FE est un ExtBillUpdate du brouillon (ACTION Submit), jamais un create, jamais un paiement. Le contrôle ERP n’accepte que STATE Draft et refuse EINVOICESTATUS Refused, Disputed, Rejected by the platform.
- #1947 LEÇON : le refus du matin « Sélectionner une Fournisseurdimension » vient d’un ExtBillUpdate sans VENDORID de ligne. Sage a examiné les lignes. Le brouillon est resté Draft. MESSAGE_REJOUABLE masque la phrase Sage : elle est dans le journal, sur l’exception précédente.
- #1948 LEÇON : sans LINE_NO, Sage ajoute une ligne ; avec LINE_NO, il modifie ; une ligne absente du bloc APBILLITEMS est supprimée. La ligne de taxe (PARENTENTRY) n’est pas renvoyée.
- #1951 LEÇON : le plantage « Array to string conversion » est avant l’envoi. Cet essai n’a rien écrit dans Sage.
- #1953 LEÇON : le correctif laisse passer l’envoi. Le 16/10 14:38 est le premier ExtBillUpdate avec LINE_NO et VENDORID de ligne qui atteint Sage.
- #1845 : l’import lit STATE, INVOICETYPE, EINVOICESTATUS. Le statut repris en base est EINVOICESTATUS. Les essais d’import modélisent une FE reçue avec EINVOICESTATUS = Made available.
- #1836 : STATE et EINVOICESTATUS sont deux champs. L’inspection DSI est en lecture seule.
- #1958 / #1959 : doublon d’une facture déjà liée à son dépôt. Hors du refus Sage. Le repli de rapprochement ne doit pas relancer ce contrôle ni recréer de facture.

Le prompt contenait le repère « coller ici la sortie de la commande tinker des champs du brouillon ». Cette sortie n’était pas dans le message.

## SYNTHÈSE

### Constat

Aucun appel Sage n’a été fait depuis cet environnement : il n’y a ni PHP, ni fichier d’environnement, ni identifiant Intacct. La lecture autorisée n’a donc pas été exécutée. Aucune écriture en base. Les valeurs ci-dessous viennent du prompt, du code qui a laissé passer l’appel, et de la documentation Sage Intacct France (aide « Receive e-invoices », notes 2026 R2 / R3, page développeur Update Bill).

| Champ Sage | Rôle | Valeur connue pour 2660201 le 16/10 14:38 |
| --- | --- | --- |
| STATE | Cycle de la facture fournisseur (Draft, Submitted, Posted, Declined…) | Draft, relu juste avant l’envoi |
| INVOICETYPE | Type de pièce | E-Invoice (c’est une FE importée ; le flux #1853 ne part que dans ce cas) |
| EINVOICESTATUS | Statut du cycle facture électronique, distinct de STATE. Libellé d’écran : « E-invoice status » / « Statut de la facture électronique » | Non relue ici. L’appel a passé `controlerAvantEnvoi` puis a atteint `IntacctService.php:1951`. Donc, au moment de l’envoi, cette valeur n’était pas Refused, ni Disputed, ni Rejected by the platform. STATE était Draft. |
| Lignes APBILLITEM | Contenu légal reçu | Ligne 1 : 58,26. Ligne 3 : taxe 0, PARENTENTRY = ligne 1 |
| WHENMODIFIED | Dernière écriture réussie | Non relue. Un refus API annulé ne la met en général pas à jour |

Valeurs documentées de EINVOICESTATUS pour une facture reçue (aide Sage, facturation électronique France) : Submitted, Made available, Approved, Partially approved, Disputed, Refused, Payment sent, Payment received. L’aide des factures émises ajoute In transit, In hand, Rejected. L’import Hectarion modélise la réception normale par Made available. Ce n’est pas une mesure sur 2660201.

La phrase citée n’est pas un texte Hectarion. `throwIfIntacctError` (`IntacctService.php:1942-1951`) relève `description2`, puis `description`, puis `correction`, et la jette telle quelle. L’écran, lui, montre ensuite le message court : « L'envoi n'a pas abouti. Le brouillon est toujours en préparation… » si la relecture après échec trouve encore STATE Draft (`ComptabilisationController.php:2015-2016`). La phrase Sage est l’exception précédente, dans le journal.

La phrase exacte n’apparaît pas dans l’aide publique consultée. Le sens, recoupé avec cette aide : Sage interdit de modifier, supprimer ou extourner une facture électronique en dehors de deux issues. L’une est l’état brouillon du cycle pièce (STATE). L’autre est le refus du cycle électronique (EINVOICESTATUS = Refused ; l’aide précise qu’une facture refusée reste en Draft). Ici STATE était déjà Draft, et le contrôle ERP prouve que la facture n’était pas refusée. La clause qui s’applique est donc le cycle électronique : une FE reçue et non refusée ne se réécrit pas par un update de lignes.

### Ce que Sage autorise sur une FE reçue

D’après l’aide « Receive e-invoices » et « Review and post incoming transactions » (France) :

- La pièce arrive en analyse, puis en brouillon dans Comptes fournisseurs > Transactions automatisées.
- Tant qu’elle est brouillon, l’écran permet de revoir la pièce, de renseigner le compte et le détail de taxe par ligne, puis d’enregistrer (Draft) ou d’accepter.
- Accepter : Soumettre si un circuit d’approbation existe, Comptabiliser (Post) sinon.
- Contester et Refuser sont des actions d’écran, avec un motif. Elles préviennent le fournisseur. Refuser laisse STATE = Draft.
- Une fois comptabilisée, la pièce part vers la plateforme agréée et ne se modifie plus.
- L’API publique d’update APBILL ne documente que ACTION Draft et ACTION Submit. Elle ne documente ni Post, ni Dispute, ni Refuse.
- Les Smart Rules et Smart Events ne sont pas pris en charge sur la facturation électronique des entités françaises. Le message ne se contourne pas par une règle société.

L’aide autorise donc, sur un brouillon reçu : compléter l’imputation (compte, taxe, dimensions), enregistrer, soumettre ou comptabiliser, contester, refuser. Elle n’autorise pas à réécrire le document légal (montants, suppression de la ligne de taxe générée) une fois la facture mise à disposition et non refusée.

### Pourquoi le matin et 14:38 ne disent pas la même chose

Le flux #1853 construit un seul update (`ExtBillUpdate.php:60-67`) : RECORDNO, VENDORID d’en-tête, WHENDUE, ACTION Submit, bloc APBILLITEMS.

Deux payloads différents ont atteint Sage :

- Matin, avant #1948 : APBILLITEMS sans LINE_NO et sans VENDORID de ligne. Sage traite une ligne sans LINE_NO comme un ajout. La dimension Fournisseur manque. Sage s’arrête sur « Sélectionner une Fournisseurdimension » avant la règle de verrouillage. La transaction est rejetée. STATE reste Draft.
- #1951 : exception PHP dans `alignerLignesAvecBrouillon`, avant `envoyer`. Aucun XML parti.
- 16/10 14:38, après #1953 : la ligne 1 part avec LINE_NO 1, VENDORID, TRX_AMOUNT et TAXENTRIES. La ligne 3 (PARENTENTRY) est omise : `alignerLignesAvecBrouillon` saute PARENTENTRY, et `ExtBillUpdate` ne réémet pas une ligne de taxe. D’après la page Update Bill et la leçon #1948, une ligne absente du bloc est supprimée, une ligne avec LINE_NO est modifiée. La dimension Fournisseur est cette fois renseignée. Sage franchit ce contrôle et applique la règle de la facture électronique : modification et suppression interdites.

Le changement de phrase s’explique par le changement de payload, sans que le statut ait besoin d’avoir bougé. Un changement de statut le même jour reste possible (action dans Sage, ou passage de cycle côté plateforme, par exemple Made available vers In hand). Il se lirait sur WHENMODIFIED et EINVOICESTATUS. Ces deux champs n’ont pas été relus ici. La lecture unitaire actuelle (`FactureElectroniqueSage.php:122-123`) demande RECORDNO, RECORDID, STATE, INVOICETYPE, EINVOICESTATUS, VENDORID, WHENCREATED, WHENDUE, TOTALENTERED, SUPDOCID, MEGAENTITYID. Elle contient EINVOICESTATUS et WHENCREATED. Elle ne demande pas WHENMODIFIED.

### Le flux #1853 est-il possible ?

Sous la forme actuelle, non, pour une FE reçue non refusée. ACTION Submit avec réécriture des lignes et suppression de la ligne de taxe est précisément une modification et une suppression. Sage le refuse. Le contrôle ERP laisse passer ce cas : il ne bloque que trois statuts électroniques, et le test de succès fabrique EINVOICESTATUS = Accepted, valeur qui n’est pas dans la table d’aide. Aucun test n’appelle Sage.

Chemin à valider ensuite, sur ce seul RECORDNO, toujours en update :

1. Relire d’abord, sans rien écrire, les champs manquants (bloc ci-dessous).
2. Si STATE est encore Draft et que EINVOICESTATUS est un statut de réception encore ouvert (Made available, ou la valeur réellement lue) : un update qui renvoie les deux lignes, y compris la taxe avec son LINE_NO et son montant 0, et qui ne change pas TRX_AMOUNT. Sur la ligne 1, seulement le compte et les dimensions (ACCOUNTNO, LOCATIONID, DEPARTMENTID, PROJECTID, CLASSID, VENDORID). Premier essai avec ACTION Draft, pour voir si l’imputation seule est acceptée. S’il passe, un second appel ACTION Submit, sans retoucher aux montants : c’est l’acceptation décrite par l’aide.
3. Si l’essai Draft est refusé avec la même phrase : l’API ne laisse pas coder la pièce. On n’insiste pas. Repli.

Repli, tant que l’essai n’a pas réussi une fois :

- La comptable comptabilise dans Sage (Transactions automatisées : compte et taxe, puis Soumettre ou Comptabiliser). Elle ne refuse pas la facture pour « débloquer » Hectarion : le refus part au fournisseur.
- Hectarion propose « Déjà comptabilisée dans Sage ». L’action relit le RECORDNO 2660201. Si STATE n’est plus Draft, elle enregistre ce même numéro dans `intacct_bill_id`, recopie STATE et EINVOICESTATUS, et passe le dépôt en comptabilisé. Si STATE est encore Draft, elle ne marque rien.
- Aucun create APBILL. Aucun second numéro.
- Écran, dès le lot suivant et jusqu’à validation de l’essai : le bouton Comptabiliser d’une facture électronique n’envoie plus cet update. Le texte affiché dit que la facture électronique se termine dans Sage, et que Hectarion la rapprochera sur le même numéro.

### Autres factures dans le même statut

Nombre et liste : non établis. Il aurait fallu une lecture. À lancer sur la prod, en lecture seule, après avoir noté la valeur EINVOICESTATUS de 2660201. Rien de ceci n’a été exécuté.

Lecture unitaire, session entité E-04 :

    read APBILL keys 2660201
    champs RECORDNO, RECORDID, STATE, INVOICETYPE, EINVOICESTATUS, VENDORID,
    WHENCREATED, WHENMODIFIED, WHENPOSTED, TOTALENTERED, TOTALDUE, MEGAENTITYID

Lignes :

    readByQuery APBILLITEM
    query RECORDKEY = '2660201'
    champs RECORDNO, LINE_NO, PARENTENTRY, ACCOUNTNO, TRX_AMOUNT, VENDORID

Les autres brouillons du même statut électronique (remplacer la valeur lue) :

    query APBILL
    INVOICETYPE = E-Invoice AND EINVOICESTATUS = valeur lue
    champs RECORDNO, STATE, EINVOICESTATUS, WHENMODIFIED, TOTALENTERED, MEGAENTITYID

Côté Hectarion, lecture seule, sans save : dépôts `facture_electronique` = 1 dont `einvoice_status` égale cette valeur, avec `intacct_bill_id` vide, colonnes id, intacct_brouillon_recordno, intacct_brouillon_entite, einvoice_status, intacct_bill_state, fe_controle_at. `einvoice_status` est le dernier statut vu par l’import, pas une preuve à la minute près.

### Risques

- Un update qui oublie la ligne 3 supprime la taxe le jour où Sage accepte la transaction. L’essai PHASE 2 doit la renvoyer telle quelle, puis relire les lignes avant tout second appel.
- ACTION Submit peut comptabiliser la pièce avec les comptes déjà dans le brouillon si les dimensions du même appel sont ignorées. Relire ACCOUNTNO et STATE après l’essai Draft, avant Submit.
- Refuser ou contester pour obtenir un droit de modification envoie un statut au fournisseur. Ce n’est pas le chemin.
- Créer une seconde facture Sage doublerait la pièce légale. Le numéro reste 2660201.
- Le rapprochement qui recréerait une facture ou relancerait le détecteur de doublon retomberait sur #1958. Il ne fait qu’écrire le numéro déjà connu.
- Laisser le bouton actuel en place refera le même refus et affichera le message court, pas la phrase Sage.

## DÉPLOIEMENT-TEST

Diagnostic seul. `git pull origin main`. Pas de migrate, pas de build, pas de `journal:sync`, pas de commande qui appelle Sage.

Quand une lecture prod sera possible, coller la sortie de la lecture unitaire (STATE, EINVOICESTATUS, WHENCREATED, WHENMODIFIED) et le décompte des autres FE du même EINVOICESTATUS. Ne pas cliquer Comptabiliser sur 2541 tant que l’essai décrit plus haut n’est pas le lot PHASE 2.

## LEÇON

STATE Draft ne rend pas une facture électronique modifiable. Le verrou est le cycle EINVOICESTATUS : une FE reçue et non refusée refuse la modification et la suppression de lignes. Le flux #1853 (APBILLITEMS + LINE_NO + omission de la taxe + ACTION Submit) est cette modification. Le refus « Fournisseurdimension » du matin était un contrôle plus tôt dans le même update, sur un payload sans LINE_NO. MESSAGE_REJOUABLE continue de cacher la phrase Sage. La valeur EINVOICESTATUS de 2660201 et le nombre de FE dans le même état restent à lire ; ils n’étaient ni dans le prompt ni accessibles depuis cet environnement.
