
Votre ERP sur IBM i gère déjà la facturation de votre entreprise. Pour passer à la facturation électronique, il n’est pas forcément nécessaire de remplacer votre application ni de revoir vos processus en profondeur. Il est possible de connecter votre programme de facturation à une plateforme agréée (PA) et d’automatiser l’envoi des factures, tout en conservant les données et les traitements existants.
Voici les principales étapes d’une intégration directement depuis votre environnement IBM i.
1. Choisir une plateforme agréée
La PA choisie doit proposer des API compatibles avec votre intégration. Selon son offre, ces API peuvent permettre de :
- déposer les factures électroniques ;
- vérifier les coordonnées du destinataire dans les annuaires concernés ;
- consulter les statuts et événements de la facture ;
- configurer un webhook pour recevoir les événements de cycle de vie.
Les formats, profils, règles de validation et mécanismes d’authentification varient selon la PA. Il faut donc obtenir sa documentation technique avant de figer l’implémentation.
2. Générer le fichier UBL avec RPGLE et CGIDEV2
Une approche simple consiste à séparer le modèle XML de la logique métier :
- Le modèle UBL est enregistré comme fichier texte dans l’IFS.
- Il contient des balises XML et des marqueurs CGIDEV2.
- Le RPGLE lit les données de facture dans DB2 for i.
- Le programme attribue les valeurs aux marqueurs et écrit les sections du document.
CGIDEV2 propose notamment getHtmlIfs pour charger un modèle depuis l’IFS, updHtmlVar pour affecter une valeur à un marqueur et wrtSection pour écrire une section dans le tampon de sortie. Ces mécanismes peuvent produire du XML, même si la bibliothèque est historiquement orientée vers la génération de pages HTML. (easy400.net)
Modèle XML avec sections et marqueurs
Voici un exemple volontairement réduit. Il illustre le mécanisme CGIDEV2 ; il ne constitue pas à lui seul une facture UBL complète ni nécessairement valide pour le profil choisi.
/$Header
<?xml version="1.0" encoding="UTF-8"?>
<Invoice
xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:CustomizationID>/%CustomizationID%/</cbc:CustomizationID>
<cbc:ProfileID>/%ProfileID%/</cbc:ProfileID>
<cbc:ID>/%InvoiceNumber%/</cbc:ID>
<cbc:IssueDate>/%IssueDate%/</cbc:IssueDate>
<cbc:DocumentCurrencyCode>/%Currency%/</cbc:DocumentCurrencyCode>
<cac:AccountingSupplierParty>
<cac:Party>
<cbc:EndpointID>/%SupplierEndpoint%/</cbc:EndpointID>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cbc:EndpointID>/%CustomerEndpoint%/</cbc:EndpointID>
</cac:Party>
</cac:AccountingCustomerParty>
/$Lines
<cac:InvoiceLine>
<cbc:ID>/%LineNumber%/</cbc:ID>
<cbc:InvoicedQuantity unitCode="/%UnitCode%/">/%Quantity%/</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="/%Currency%/">/%LineAmount%/</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>/%ItemName%/</cbc:Name>
</cac:Item>
</cac:InvoiceLine>
/$Attachments
<cac:AdditionalDocumentReference>
<cbc:ID>/%AttachmentId%/</cbc:ID>
<cac:Attachment>
<cbc:EmbeddedDocumentBinaryObject
mimeCode="/%MimeCode%/"
filename="/%FileName%/">/%Base64Content%/</cbc:EmbeddedDocumentBinaryObject>
</cac:Attachment>
</cac:AdditionalDocumentReference>
/$Footer
</Invoice>
Dans la convention CGIDEV2 par défaut, les sections commencent par /$ et les marqueurs à remplacer sont écrits /%Nom%/. La section Lines sera écrite une fois par ligne de facture ; Attachments, une fois par pièce jointe. Le séparateur de section par défaut peut poser problème avec certains CCSID : CGIDEV2 permet d’en configurer d’autres.
Esquisse du traitement RPGLE
Le code suivant donne le principe, mais les prototypes exacts, la conversion des champs et l’écriture du fichier dépendent de votre environnement CGIDEV2 et de votre architecture :
**free
// Charger le modèle XML depuis l'IFS
getHtmlIfs('/facturation/modeles/Invoice.xml');
// Renseigner les variables d'en-tête
updHtmlVar('CustomizationID' : customizationId);
updHtmlVar('ProfileID' : profileId);
updHtmlVar('InvoiceNumber' : invoiceNumber);
updHtmlVar('IssueDate' : issueDateIso);
updHtmlVar('Currency' : currencyCode);
// Écrire l'en-tête dans le tampon
wrtSection('Header');
// Écrire une section par ligne de facture
for i = 1 to lineCount;
updHtmlVar('LineNumber' : %char(i));
updHtmlVar('UnitCode' : unitCode(i));
updHtmlVar('Quantity' : quantityIso(i));
updHtmlVar('LineAmount' : lineAmountIso(i));
updHtmlVar('ItemName' : itemName(i));
wrtSection('Lines');
endfor;
// Écrire une section par pièce jointe
// Les valeurs AttachmentId, MimeCode, FileName et Base64Content
// sont renseignées par le traitement des fichiers.
wrtSection('Footer');
// Écrire ou récupérer le contenu produit, selon l'implémentation retenue.
CGIDEV2 fournit aussi updHtmlVar2, qui accepte un pointeur et une longueur et peut être utile pour des données de substitution plus volumineuses. Cela ne dispense pas de gérer les limites de mémoire et de tampon de votre programme.
Points importants sur les valeurs remplacées
- Échappez les caractères XML dans les données textuelles :
&,<,>et, selon le contexte, les guillemets. - Formatez les nombres et les dates selon les attentes XML et le profil UBL ; évitez les formats dépendant de la langue du travail.
- Maîtrisez l’encodage du fichier et assurez-vous qu’il correspond à la déclaration XML, par exemple UTF-8.
- Initialisez chaque variable à chaque section répétée pour éviter de réutiliser par erreur la valeur d’une ligne précédente.
- Si une valeur est manquante, faites échouer ou mettez en anomalie la facture plutôt que de laisser une valeur de substitution implicite dans le document.
- Vérifiez la longueur maximale des champs et des tampons CGIDEV2, notamment pour le Base64 des fichiers.
3. Ajouter un ou plusieurs PDF en pièces jointes
Un PDF peut être intégré dans l’UBL sous forme de données binaires encodées en Base64. Dans UBL, l’élément cac:AdditionalDocumentReference peut contenir un cac:Attachment, avec le contenu dans cbc:EmbeddedDocumentBinaryObject. Cet élément peut porter le nom de fichier et le type MIME, par exemple application/pdf. (docs.oasis-open.org)
Lire le PDF en mode binaire
Il est important de lire le PDF comme des octets binaires, sans conversion préalable de CCSID. IBM documente QSYS2.IFS_READ_BINARY pour renvoyer les données de l’IFS sous forme binaire, telles qu’elles sont stockées. QSYS2.BASE64_ENCODE convertit ensuite une valeur binaire en texte Base64, renvoyé en CLOB CCSID 1208. (ibm.com)
Exemple SQL de principe :
dcl-s base64Content SQLTYPE(CLOB:10000000);
Exec SQL
Values BASE64_ENCODE(
CAST(GET_BLOB_FROM_FILE('/facturation/pdf/INV-2026-0042.pdf') AS BLOB(10M))
) into :base64Content;
Pour un fichier de taille raisonnable, cette approche permet d’obtenir le contenu Base64. En RPGLE, le résultat peut être traité via SQL embarqué, un CLOB ou un locator LOB selon la manière dont l’application est construite.
Un locator référence le BLOB sans nécessairement charger tout son contenu dans une variable RPG ; IBM documente sa déclaration et son emploi dans les applications ILE RPG. (ibm.com)
Le flux logique est donc :
Fichier PDF de l’IFS
↓
Lecture binaire / valeur BLOB
↓
Encodage Base64
↓
Insertion du texte Base64 dans l’élément UBL
Ajouter l’élément au modèle XML
Le modèle de facture peut contenir une section répétable dédiée aux pièces jointes :
/$Attachment
<cac:AdditionalDocumentReference>
<cbc:ID>/%AttachmentId%/</cbc:ID>
<cac:Attachment>
<cbc:EmbeddedDocumentBinaryObject
mimeCode="/%MimeCode%/"
filename="/%FileName%/">/%Base64Content%/</cbc:EmbeddedDocumentBinaryObject>
</cac:Attachment>
</cac:AdditionalDocumentReference>
Le RPGLE renseigne alors, pour chaque document, l’identifiant, le type MIME — par exemple application/pdf —, le nom du fichier et le contenu encodé.
Attention à CGIDEV2 : la taille d’un PDF augmente d’environ un tiers après encodage Base64. L’ajout du Base64 dans une variable CGIDEV2 peut aussi rencontrer des limites de taille de variable ou de tampon. Pour des fichiers volumineux, évitez de charger tout le contenu dans une variable de longueur fixe. Préférez une génération en flux ou par blocs, avec un mécanisme maîtrisant la taille des tampons et l’écriture du XML. Le comportement exact dépend de la version et de la configuration CGIDEV2.
Ajouter plusieurs pièces jointes
Le même mécanisme permet d’ajouter plusieurs pièces jointes à la même facture. Le RPGLE parcourt la liste des documents associés, puis, pour chaque fichier :
- lit le fichier en binaire ;
- encode son contenu en Base64 ;
- renseigne
AttachmentId,MimeCode,FileNameetBase64Content; - écrit la section
Attachments.
Vérifiez cependant les limites de taille de la PA, du profil UBL et de votre méthode de génération. Le Base64 augmente le volume des données d’environ un tiers. Avec de gros fichiers ou plusieurs pièces jointes, évitez de placer tout le contenu dans une variable de longueur fixe ou un tampon insuffisant. updHtmlVar2 peut aider pour certaines grandes valeurs, mais il faut vérifier les limites applicables et tester le volume maximal avec votre version de CGIDEV2.
Le fait qu’UBL permette d’intégrer une pièce jointe ne garantit pas que chaque PA ou profil accepte tous les types de documents ou toutes les tailles. Ce point doit être confirmé auprès de la PA.
4. Valider le fichier UBL
Avant tout dépôt, validez le document généré. La validation devrait couvrir au minimum :
- Le XML : syntaxe correcte et encodage cohérent.
- Le schéma XSD : structure conforme à la version UBL utilisée.
- Le Schematron du profil : règles métier et contraintes propres au profil retenu.
- Les données : montants, taxes, identifiants, adresses et pièces jointes cohérents avec la facture ERP.
Le script Python de validation peut être lancé de manière synchrone depuis le traitement IBM i. Si la validation échoue, le RPGLE enregistre l’anomalie et bloque le dépôt à la PA. Les messages de validation doivent être conservés pour faciliter le diagnostic.
Après génération, vérifiez aussi que chaque chaîne Base64 peut être décodée et que le fichier obtenu correspond au PDF d’origine.
5. Vérifier le destinataire et transmettre la facture
Avant l’envoi, le RPGLE peut appeler l’API de la PA pour vérifier l’adresse électronique ou l’identifiant du destinataire, par exemple dans l’annuaire applicable au flux et au profil considérés.
(Voir notre article Optimiser les appels API en RPG).
Si le destinataire est reconnu et que les validations sont passées, le programme transmet le XML à l’API de la PA. Conservez l’identifiant de dépôt ou l’accusé de réception fourni par la plateforme afin de rapprocher la réponse de la facture ERP.
6. Recevoir les événements de cycle de vie grâce à un webhook
L’envoi de la facture ne constitue qu’une partie de l’intégration. Pour récupérer les événements de cycle de vie — par exemple les statuts communiqués par la PA — il faut également prévoir un point d’entrée HTTP que la plateforme pourra appeler.
Ce mécanisme est généralement un webhook : la PA envoie une requête HTTP à une URL configurée dans son interface ou dans ses paramètres d’API. Cette URL doit être accessible depuis l’extérieur de votre réseau, ou depuis les réseaux autorisés par la PA.
Activer une instance IBM HTTP Server sur IBM i
IBM HTTP Server for i, basé sur Apache, se configure et se pilote depuis l’interface d’administration Web d’IBM i. Si cette interface n’est pas déjà active, elle peut être démarrée depuis une ligne de commande CL avec :
STRTCPSVR SERVER(*HTTP) HTTPSVR(*ADMIN)
L’administration Web d’IBM i est ensuite accessible depuis un navigateur. IBM documente l’accès à cette interface ainsi que la création d’une instance HTTP Server. (ibm.com)
Depuis l’administration Web, créez une instance IBM HTTP Server si vous n’en avez pas déjà une, puis configurez son adresse d’écoute, son port et ses journaux. Une fois l’instance créée, vous pouvez la démarrer depuis l’interface d’administration ou avec la commande CL suivante, en remplaçant NOM_INSTANCE par le nom de votre serveur :
STRTCPSVR SERVER(*HTTP) HTTPSVR(NOM_INSTANCE)
Pour arrêter l’instance, utilisez :
ENDTCPSVR SERVER(*HTTP) HTTPSVR(NOM_INSTANCE)
IBM indique que chaque instance HTTP Server fonctionne dans le sous-système QHTTPSVR et que ces commandes permettent de démarrer et d’arrêter une instance configurée. (ibm.com)
Associer une URL à un programme de traitement
Il faut ensuite définir la route — l’URL — que la PA appellera, par exemple :
https://webhooks.votre-domaine.fr/pa/cycle-de-vie
L’instance Apache reçoit la requête à cette adresse et la dirige vers un programme chargé de traiter le message. Sur IBM i, plusieurs architectures sont possibles : un programme CGI ILE RPG, une application ou un service intermédiaire, ou encore un reverse proxy vers un service dédié.
IBM HTTP Server for i prend notamment en charge les programmes CGI en ILE RPG. Leur exposition nécessite une configuration adaptée dans le serveur, notamment une directive de type ScriptAlias, ainsi que les autorisations nécessaires sur le programme et les objets auxquels il accède. (ibm.com)
Exemple indicatif de routage CGI :
ScriptAlias /pa/ /QSYS.LIB/MA_BIBLI.LIB/CGI.PGM/
Cette configuration est un exemple de principe, pas une configuration prête à copier-coller : le chemin, le programme CGI, les paramètres HTTP et la méthode de traitement doivent être adaptés à votre installation et au format précis des requêtes de la PA. Le programme qui reçoit l’appel devra notamment lire le corps de la requête, identifier la facture concernée, enregistrer l’événement et retourner à la PA une réponse HTTP appropriée.
Sécuriser le point d’entrée
Comme cette URL reçoit des appels venant de l’extérieur, elle doit être conçue comme une interface d’échange sécurisée. En pratique, il faut notamment prévoir :
- HTTPS avec un certificat valide ;
- le mécanisme d’authentification ou de vérification prévu par la PA, par exemple une signature ou un secret partagé si la plateforme le propose ;
- le filtrage réseau disponible — par exemple une liste d’adresses IP autorisées, si la PA fournit les plages concernées ;
- la vérification des données reçues et la limitation des informations consignées dans les journaux ;
- un traitement idempotent, afin qu’un même événement envoyé plusieurs fois ne crée pas de doublons.
Il est également préférable que le point d’entrée enregistre rapidement l’événement de façon fiable, puis le traite dans un programme séparé ou une file d’attente si le traitement métier est plus long. Le comportement attendu lorsqu’un événement est invalide ou temporairement impossible à traiter doit être défini en accord avec les règles de la PA, notamment pour déterminer le code HTTP à retourner et les éventuelles tentatives de renvoi.
Configurer l’URL dans la PA et tester le cycle de vie
Une fois l’URL déployée et joignable depuis l’extérieur, renseignez-la dans la configuration webhook de la PA, avec les événements à recevoir et le mécanisme d’authentification demandé. L’adresse doit être accessible par la PA : une URL disponible uniquement sur le réseau interne de l’entreprise ne suffira pas.
Effectuez ensuite un test de bout en bout : la PA appelle l’URL, le serveur IBM i reçoit la requête, le programme de traitement enregistre l’événement et l’ERP peut le rattacher à la facture grâce à son identifiant ou à la référence transmise.
Un flux automatisé depuis l’ERP
L’intégration peut suivre ce déroulement :
Lecture des données de facture dans DB2 for i
↓
Chargement du modèle XML avec CGIDEV2
↓
Remplacement des variables et écriture des sections
↓
Génération du fichier UBL sur l’IFS
↓
Validation XML, XSD et Schematron
↓
Vérification du destinataire via l’API de la PA
↓
Dépôt de la facture auprès de la PA
↓
Réception des événements de cycle de vie par webhook
Cette approche permet de conserver l’ERP sur IBM i et de faire évoluer progressivement le processus de facturation. La structure XML reste dans un modèle maintenable, tandis que le RPGLE pilote l’extraction des données et la génération du document. Des composants en Python peuvent assurer la validation, et un point d’entrée HTTP peut recevoir les événements de la PA.
L’ensemble s’intègre ainsi au système existant, sous réserve de valider le profil UBL, la sécurité et les modalités propres à la plateforme choisie.



0 commentaire