L'import des factures et notes de crédit provenant de Peppol peut se faire dans l'interface de Mercator. Il est aussi possible d'automatiser totalement le processus. Le processus déclenchant de cet import automatique peut être une tâche en mode console. Dans ce code, il faut utiliser les outils mis à disposition via le PeppolBoxHelper.
La méthode ImportIntoBilling du MercatorUi.Forms.Other.OtherClasses.PeppolBoxHelper.PeppolMessage est utilisée. Elle attend un paramètre de type ImportFromEinvoiceDescriptor qui contient ces propriétés :
- bool Silent : à mettre à true pour un import sans interface utilisateur.
- string Journal : le journal comptable de destination. Obligatoire si Silent vaut true. Ce journal peut être une séquence de factures ou de brouillons (si Silent est activé).
- string ReplacementItemId : le S_ID d'un article à utiliser temporairement si un article ne peut être identifié par le processus de reconnaissance du contenu XML.
- Engine.Gescom.Tools.BillingDocDescriptor[] PreviousDocs : la liste des commandes / livraisons du fournisseur identifié dans l'eInvoice à augmenter dans cette facture. Cette liste doit contenir uniquement des commandes ou uniquement des livraisons. Ce paramètre peut être laissé à null. Il doit être null si on importe vers un brouillon.
Il contient aussi ces propriétés en lecture seule, qui sont populées lors du processus d'import :
- string Warning : le message éventuel, tel que celui affiché lorsqu'on importe dans l'interface de Mercator. Par exemple : "Différence montants HTVA".
- DataRow[] ItemsNotFound : la liste des articles qui n'ont pu être identifiés par le processus de reconnaissance du contenu XML et qui ont fait l'objet d'une création automatique d'articles.
La méthode ImportIntoBilling renvoie un BillingEngine. Ce BillingEngine n'est pas déjà sauvegardé. Il est dès lors aisé d'apporter toutes les modifications souhaitées avant d'appeler sa méthode Save. Le fichier PDF inclus dans le XML sera automatiquement joint à l'écriture par Mercator (dans les fichiers SQL). Le contenu XML sera aussi attaché en tant que fichier XML. Ce qui permet de supprimer le message de la PeppolBox sans inquiétude.
Lors d'une importation en mode silencieux, le contexte du BillingEngine est ContextEnum.ImportEinvoiceSilent.
Le code ci-dessous reprend un exemple simple d'import vers un brouillon d'achat :
public void ImportEinvoiceIntoBilling1()
{
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);
return;
}
var message = peppolBoxHelper.Messages.FirstOrDefault(m => m.IsInvoiceOrCreditNote); // mettre ici une logique de sélection du message à importer
if (message == null)
{
MercatorUi.Globals.MercatorTasksToMain.Log("Message non trouvé", isError: true);
return;
}
MercatorUi.Forms.Gescom.GescomClasses.ImportFromEinvoiceDescriptor importFromEinvoiceDescriptor = new MercatorUi.Forms.Gescom.GescomClasses.ImportFromEinvoiceDescriptor
{
Silent = true,
Journal = "BrouA", // importer vers un brouillon d'achats
ReplacementItemId = "ARTIMC6XS9" // si l'article n'est pas identifier, cet article sera utilisé
};
using (MercatorUi.Engine.Gescom.BillingEngine billingEngine = message.ImportIntoBilling(importFromEinvoiceDescriptor, out string error))
{
if (error != null)
{
MercatorUi.Globals.MercatorTasksToMain.Log(error, isError: true);
return;
}
billingEngine.PeppolBoxId = message.Id;
// ici on peut ajouter dans l'écriture comptable des informations venant du contenu XML . Par exemple le nom et l'adresse mail du contact
MercatorPeppol.ReceivedDoc.ParseContentRet parsedContent = message.ReceivedDoc.ParseContent(MercatorUi.Globals.Langue);
billingEngine.PiedsVRecord.NOTE1 = parsedContent.XmlSelectNodes("cac:AccountingSupplierParty/cac:Party/cac:Contact/cbc:Name").FirstOrDefault()?.InnerText + " "
+ parsedContent.XmlSelectNodes("cac:AccountingSupplierParty/cac:Party/cac:Contact/cbc:ElectronicMail").FirstOrDefault()?.InnerText;
// on récupère les warnings éventuels
if (!string.IsNullOrEmpty(importFromEinvoiceDescriptor.Warning))
billingEngine.PiedsVRecord.NOTE2 = importFromEinvoiceDescriptor.Warning;
if (!billingEngine.Save())
{
MercatorUi.Globals.MercatorTasksToMain.Log("Erreur lors de l'enregistrement du document : " + billingEngine.LastError, isError: true);
return;
}
if (!message.RemoveFromListAndDb()) // supprimer le message de la PeppolBox
{
MercatorUi.Globals.MercatorTasksToMain.Log("Erreur lors de la suppression du message : " + Api.LastError, isError: true);
return;
}
MercatorUi.Globals.MercatorTasksToMain.Log(string.Format("Import terminé {0} {1} correctement", billingEngine.Journal, billingEngine.Piece));
}
}
}
Dans ce second exemple, l'eInvoice est importée dans une séquence de factures. Le code contient une identification de la commande liée à cette facture. Cette identification se fait sur base de la zone BuyerReference qui doit contenir le numéro de la commande. Une logique plus sophistiquée pourra être mise en place. Cette commande sera augmentée dans la facture importée.
public void ImportEinvoiceIntoBilling2()
{
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);
return;
}
var message = peppolBoxHelper.Messages.FirstOrDefault(m => m.IsInvoiceOrCreditNote);
if (message == null)
{
MercatorUi.Globals.MercatorTasksToMain.Log("Message non trouvé", isError: true);
return;
}
MercatorPeppol.ReceivedDoc.ParseContentRet parsedContent = message.ReceivedDoc.ParseContent(MercatorUi.Globals.Langue);
if (string.IsNullOrEmpty(parsedContent.BuyerReference) || string.IsNullOrEmpty(Api.NumOnly(parsedContent.BuyerReference)) || !Int64.TryParse(Api.NumOnly(parsedContent.BuyerReference), out Int64 pieceCommande))
{
MercatorUi.Globals.MercatorTasksToMain.Log("La référence est vide ou invalide. Impossible de trouver la commande. " + parsedContent.BuyerReference, isError: true);
return;
}
List<(string id, string journal, Int64 piece, Int16 type)> pieds_a = Api.Zselect<(string id, string journal, Int64 piece, Int16 type)>(MercatorUi.Globals.RepData,
"select id,journal,piece,type from PIEDS_A (NOLOCK) where (journal='COMMF') and (piece=@piece) and (pieds_a.n_lignes2 > 0)",
new MercatorSqlParam("@piece", pieceCommande));
if (pieds_a == null)
{
MercatorUi.Globals.MercatorTasksToMain.Log("Recherche commande : " + Api.LastError, isError: true);
return;
}
if (!pieds_a.Any())
{
MercatorUi.Globals.MercatorTasksToMain.Log("Commande non trouvée : " + pieceCommande, isError: true);
return;
}
MercatorUi.Forms.Gescom.GescomClasses.ImportFromEinvoiceDescriptor importFromEinvoiceDescriptor = new MercatorUi.Forms.Gescom.GescomClasses.ImportFromEinvoiceDescriptor
{
Silent = true,
Journal = "FactF",
ReplacementItemId = "ARTIMC6XS9",
PreviousDocs = new MercatorUi.Engine.Gescom.Tools.BillingDocDescriptor[] { new MercatorUi.Engine.Gescom.Tools.BillingDocDescriptor(MercatorUi.Engine.Gescom.Billing.TypeVAEnum.A, pieds_a[0].type, pieds_a[0].id, pieds_a[0].journal, pieds_a[0].piece) }
};
using (MercatorUi.Engine.Gescom.BillingEngine billingEngine = message.ImportIntoBilling(importFromEinvoiceDescriptor, out string error))
{
if (error != null)
{
MercatorUi.Globals.MercatorTasksToMain.Log(error, isError: true);
return;
}
if (!string.IsNullOrEmpty(importFromEinvoiceDescriptor.Warning))
billingEngine.PiedsVRecord.NOTE1 = importFromEinvoiceDescriptor.Warning;
if (!billingEngine.Save())
{
MercatorUi.Globals.MercatorTasksToMain.Log("Erreur lors de l'enregistrement du document : " + billingEngine.LastError, isError: true);
return;
}
if (!message.RemoveFromListAndDb())
{
MercatorUi.Globals.MercatorTasksToMain.Log("Erreur lors de la suppression du message : " + Api.LastError, isError: true);
return;
}
MercatorUi.Globals.MercatorTasksToMain.Log(string.Format("Import terminé {0} {1} correctement", billingEngine.Journal, billingEngine.Piece));
}
}
}