Mercator contient la classe MercatorUi.Forms.Other.OtherClasses.PeppolBoxHelper qui offre une série d'outils s'appliquant à la réception de messages provenant du réseau Peppol.
Cette classe est IDisposable. Elle répond à ces trois interfaces :
- MercatorUi.ICustomizers.IPeppolBoxHelperCreated : méthode void PeppolBoxHelperCreated(Forms.Other.OtherClasses.PeppolBoxHelper peppolBoxHelper) appelée lors de l'initialisation d'un objet de ce type
- MercatorUi.ICustomizers.IPeppolBoxHelperClosed : méthode void PeppolBoxHelperClosed(Forms.Other.OtherClasses.PeppolBoxHelper peppolBoxHelper) appelée lorsque cet objet est disposé.
- MercatorUi.ICustomizers.IStringUpdater : pour modifier éventuellement la sélection des messages venant de la table PEPPPOL_RECEIVED_MESSSAGES
Pour personnaliser le comportement de cet objet, il faut créer un customizer PeppolBox :
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Linq;
using MercatorApi;
using MercatorExtensions;
using MercatorUi;
using MercatorDatabase;
using System.Xml;
// <CompileWithRoslyn />
namespace PeppolBox
{
public class Customizer : MercatorUi.ICustomizers.IPeppolBoxHelperCreated, MercatorUi.ICustomizers.IPeppolBoxHelperClosed
{
public void PeppolBoxHelperCreated(MercatorUi.Forms.Other.OtherClasses.PeppolBoxHelper peppolBoxHelper)
{
...
}
public void PeppolBoxHelperClosed(MercatorUi.Forms.Other.OtherClasses.PeppolBoxHelper peppolBoxHelper)
{
...
}
}
}
Cette classe contient ces propriétés publiques :
- DataTable DataTable : les données derrière la grille de la PeppoBox
- PeppolMessagesCollection Messages : les mêmes données représentées sous la forme d'objet de type PeppolMessage
- PeppolBoxForm PeppolBoxForm : la fenêtre de la PeppolBox. Null si le helper a été instancié de manière autonome (cfr. infra).
Les deux premières propriétés sont deux représentations différentes des mêmes données. En conséquence, la modification ou suppression d'une DataRow dans la DataTable entraîne automatiquement la modification ou suppression du message correspond dans la collection. Et vice versa. Pour simplifier le code custom, il est recommandé d'utiliser la collection.
Elle contient ces méthodes publiques :
- Pour le téléchargement des nouveaux messages
- bool Download()
- Task<(bool result, string error)> DownloadAsync()
- Pour la suppression des messages contenus dans Datatable / Messages (donc les messages visibles dans la PeppolBox) et dans la table PEPPPOL_RECEIVED_MESSSAGES de la base données
- bool RemoveAllFromListAndDb()
- Task<(bool result, string error)> RemoveAllFromListAndDbAsync()
La collection Messages, qui est IEnumerable, contient des instances de classe MercatorUi.Forms.Other.OtherClasses.PeppolMessage. Cette dernière contient ces propriétés :
- Guid Id : identifiant du message. Correspond à la clé primaire de la table PEPPPOL_RECEIVED_MESSSAGES
- DateTime Moment : la date et l'heure du transit dans le réseau Peppol
- string Message : le message Peppol sous format Json (sera utilisable via ReceivedDoc)
- string MsgType : le type de message
- bool IsNew : true si le message vient d'être reçu, false sinon
- bool IsInvoiceOrCreditNote : true si le message est une facture ou une note de crédit, false sinon
- MercatorPeppol.ReceivedDoc ReceivedDoc : représentation objet du contenu du message (cf. infra). Null si le message n'est pas une facture ou une note de crédit.
- PeppolBoxHelper ParentPeppolBoxHelper : le helper parent de ce message
- DataRow DataRow : la DataRow correspondante dans la DataTable
Et ces méthodes pour supprimer ce message de la Datatable / collection et dans la table PEPPPOL_RECEIVED_MESSSAGES de la base données :
- bool RemoveFromListAndDb()
- Task<(bool result, string error)> RemoveFromListAndDbAsync()
Et ces autres méthodes :
- StartImportIntoAccounting() : débuter l'import en comptabilité.
- ImportIntoAccounting() : effectuer l'import en comptabilité. Voir cet exemple.
- StartImportIntoBilling() : débuter l'import en gestion commerciale.
- StartInvoiceResponse() : débuter l'envoi d'une invoice response.
- ShowInvoiceOrCreditNote() : montrer la facture / note de crédit (le PDF s'il existe, sinon le contenu XML).
- ShowXml() : montrer le contenu XML.
- void ExportToXml(string xmlFileName = null) : export du document (facture / note de crédit) vers un fichier XML. Si xmlFileName est non défini, alors une boîte de dialogue de sauvegarde est présentée.
- void ExportToXmlRaw(string xmlFileName = null) : export du message brut venant du réseau Peppol vers un fichier XML. Si xmlFileName est non défini, alors une boîte de dialogue de sauvegarde est présentée.
La classe MercatorPeppol.ReceivedDoc contient notamment la méthode ParseContent qui renvoie un type MercatorPeppol.ReceivedDoc.ParseContentRet. Elle accepte ce paramètre qui, en sus de la langue souhaitée, permet de déterminer ce que l'on souhaite recevoir dans le résultat en plus du contenu XML sous la forme d'un XmlDocument : MercatorPeppol.ReceivedDoc.ParseContentEnum.WithSupplierName | MercatorPeppol.ReceivedDoc.ParseContentEnum.WithPdf | MercatorPeppol.ReceivedDoc.ParseContentEnum.WithRawContent
Si on souhaite parser le contenu XML, il est recommandé de le faire en utilisant ParseContentRet.XmlDoc plutôt que ParseContentRet.RawContent. Après parsing, il faut toujours tester si ParseContentRet.Error est null, car il n'est pas exclu qu'un message envoyé par un tiers ne soit pas valide au niveau de la syntaxe XML.
Il est aisé de localiser des nœuds dans le XmlDoc via la méthode XmlSelectNodes.
XmlNode nodeNumTva = parsedContent.XmlSelectNodes("cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID").FirstOrDefault();
Exemples :
Utilisation du PeppolBoxHelper en mode autonome
Le PeppolBoxHelper peut être instancié en dehors de la PeppolBoxForm. Il permet alors d'effectuer par code toutes les opérations qui sont disponibles dans la PeppolBoxForm.
Par exemple, ce simple code placé dans un customizer Main peut effectuer le téléchargement des messages depuis une tâche en mode console.
public void DownloadPeppolMessages()
{
MercatorUi.Globals.MercatorTasksToMain.Log("Instanciation du PeppolBoxHelper");
using (MercatorUi.Forms.Other.OtherClasses.PeppolBoxHelper peppolBoxHelper = new MercatorUi.Forms.Other.OtherClasses.PeppolBoxHelper())
{
if (peppolBoxHelper.DataTable == null)
MercatorUi.Globals.MercatorTasksToMain.Log("Erreur lors de l'initialisation du PeppolBoxHelper : " + Api.LastError, isError: true);
else if (!peppolBoxHelper.Download())
MercatorUi.Globals.MercatorTasksToMain.Log("Erreur lors de téléchargement des messages : " + Api.LastError, isError: true);
else
MercatorUi.Globals.MercatorTasksToMain.Log("Message(s) téléchargé(s) : " + peppolBoxHelper.Messages.Count(m => m.IsNew));
}
}
Il est inutile de mettre un intervalle d'exécution inférieur à 15 minutes. Le réseau Peppol a en effet une latence d'environ 15 minutes.
Dans le dernier else de ce code, on peut placer tout code qui exploite peppolBoxHelper.Messages pour effectuer un prétraitement sur ces messages.
Autre exemple : Automatiser l'import en comptabilité d'une eInvoice
Le PeppolBoxHelper contient aussi ces méthodes statiques qui sont particulièrement pertinentes en dehors de la PeppolBoxForm :
- PeppolMessage PeppolMessageFromId(Guid id) : renvoie un PeppolMessage selon l'id de la table PEPPPOL_RECEIVED_MESSSAGES
- PeppolMessage PeppolMessageFromAction(Engine.Crm.ActionEngine actionEngine) : renvoie un PeppolMessage selon le même id stocké dans actionEngine.ActionsRecord.ENTRYID
Un exemple complet d'implémentation d'une distribution automatisée des factures / notes de crédit reçues via Peppol est disponible sur cette page.
En général, lors de l'utilisation du PeppolBoxHelper en mode autonome, le code contenu dans le customizer PeppolBox n'est plus nécessaire. En effet, le code de ce customizer peut être directement placé dans le code sur mesure instanciant le PeppolBoxHelper. Dans le customizer PeppolBox, il est aisé de déterminer si le code est appelé par un PeppolBoxHelper en mode autonome : PeppolBoxHelper.PeppolBoxForm est dans ce cas null.