Bienvenue dans le manuel du plugin Invoice Radar destiné aux développeurs !
Ce guide vous aidera à créer des plugins personnalisés pour récupérer des factures et des reçus sur diverses plateformes.
Invoice Radar est un outil d'automatisation de documents qui vous aide à récupérer, télécharger et organiser des factures et des reçus à partir de diverses plateformes.
En savoir plus sur le radar des factures
Introduction
Commencer
Structure des plugins
Écrire votre premier plugin
Modèles utiles
Référence des étapes
Connaissance de base de JSON, HTML, CSS et JavaScript.
Un éditeur de texte ou IDE (par exemple, VSCode, Sublime Text).
Invoice Radar installé sur macOS ou Windows.
Téléchargez et installez Invoice Radar :
Demander l'accès à Invoice Radar
Téléchargez le plugin vierge :
Téléchargez le plugin Blank sur votre ordinateur local.
Renommez le fichier en your-plugin-name.json
.
Mettez-le dans un dossier de votre choix.
Ajoutez le plugin à Invoice Radar :
Ouvrez le radar de factures.
Accédez aux paramètres et choisissez l’onglet Available Plugins
.
Choisissez Choose Plugin Directory
et sélectionnez le dossier dans lequel vous avez enregistré le plugin.
Votre plugin devrait maintenant apparaître dans la liste des plugins disponibles.
Les plugins pour Invoice Radar sont écrits en JSON et suivent une structure spécifique. Chaque plugin se compose des sections suivantes :
Description du plugin :
Métadonnées : informations de base sur le plugin, telles que le nom, la description et l'URL de la page d'accueil.
configSchema : Propriétés de configuration que le plugin peut exiger.
Étapes de grattage :
checkAuth : étapes pour vérifier si l'utilisateur est déjà authentifié.
startAuth : étapes pour lancer le processus d'authentification.
getDocuments : étapes pour récupérer et télécharger des documents.
{ "$schema": "https://raw.githubusercontent.com/invoiceradar/plugins/main/schema.json", "id": "exemple", "nom": "Exemple de plateforme", "description": " Brève description du service.", "homepage": "https://example.com", "checkAuth": [ { "action": "navigate", "url": "https://example.com/dashboard" }, { "action": "checkElementExists", "selector": "#logout-button" } ], "startAuth": [ { "action": "navigate", "url": "https://example.com/login" }, { "action": "waitForElement", "selector": "#account-summary", "timeout": 120000 } ], "getDocuments": [ { "action": "navigate", "url": "https://example.com/billing" }, { "action": "extractAll", "selector": ".invoice-row", "variable": "invoice", "fields": { "id": { "selector": ".invoice-id" }, "date": { "selector": ".invoice-date" }, "total": { "sélecteur": ".invoice-total" }, "url": { "selector": ".invoice-download", "attribute": "href" } }, "pourChaque": [ { "action": "downloadPdf", "url": "{{invoice.url}}", "document": "{{invoice}}" } ] } ] }
Le schéma complet peut être trouvé ici.
Créons un plugin simple pour récupérer les factures d'un service hypothétique.
Définir les métadonnées :
Ces informations sont utilisées pour identifier et afficher le plugin dans Invoice Radar. L'URL de la page d'accueil est utilisée pour obtenir le favicon du service.
Notez que l' id
doit être unique et en minuscules.
{ "id": "example-service", "name": "Example Service", "description": "Brève description du service.", "homepage": "https://example.com"}
En savoir plus sur les champs de métadonnées.
Définir le schéma de configuration (facultatif) :
Le schéma de configuration définit les champs requis pour que le plugin fonctionne. Dans cet exemple, nous avons besoin d'un teamID
et password
pour nous authentifier.
Ces champs seront affichés à l'utilisateur lors de l'ajout du plugin dans Invoice Radar.
"configSchema": { "teamID": { "type": "string", "title": "Team ID", "description": "L'ID de votre équipe ou compte pour récupérer les factures.", "required": true } }
En savoir plus sur les champs du schéma de configuration.
Vérifier l'authentification :
checkAuth
contient des étapes pour vérifier si l'utilisateur est authentifié. Cela peut être fait en vérifiant l'URL ou l'existence de l'élément. La dernière étape dans checkAuth
doit être une étape de vérification.
Ces étapes sont exécutées au démarrage d'une exécution. Si l'utilisateur est déjà authentifié, le plugin ignorera le processus d'authentification et passera directement à la récupération des documents.
"checkAuth": [ { "action": "navigate", "url": "https://example.com/dashboard" }, { "action": "checkElementExists", "selector": "#logout-button" } ]
Démarrer l'authentification :
startAuth
contient les étapes pour lancer le processus d'authentification. Cela peut impliquer de naviguer vers la page de connexion et d'attendre un indicateur de connexion réussie.
Le navigateur sera visible pendant le processus d'authentification, permettant à l'utilisateur d'interagir avec le formulaire de connexion.
"startAuth": [ { "action": "navigate", "url": "https://example.com/login" }, { "action": "waitForElement", "selector": "#account-summary", "timeout": 120000 } ]
Grattez des documents :
getDocuments
contient des étapes pour récupérer et télécharger des documents. Cela peut impliquer de naviguer vers la page de facturation, d'extraire les détails de la facture et de télécharger les PDF.
"getDocuments": [ { "action": "navigate", "url": "https://example.com/billing" }, { "action": "extractAll", "selector": ".invoice-row", "variable": "invoice", "fields": { "id": { "selector": ".invoice-id" }, "date": { "selector": ".invoice-date" }, "total": { "sélecteur": ".invoice-total" }, "url": { "selector": ".invoice-download", "attribute": "href" } }, "pourChaque": [ { "action": "downloadPdf", "url": "{{invoice.url}}", "document": { "type": "invoice", "id": "{{invoice.id}}", "date": "{{invoice.date}}", "total": "{{invoice.total}}" } } ] } ]
Vous avez terminé ! :
Enregistrez le fichier et ajoutez-le à Invoice Radar. Vous pouvez maintenant exécuter le plugin pour récupérer les factures du service.
checkAuth
)De nombreux services redirigent automatiquement vers la page de connexion si l'utilisateur n'est pas authentifié. Nous pouvons utiliser ce comportement pour vérifier si l'utilisateur est authentifié.
{ "action": "navigate", "url": "https://example.com/login"}, { "action": "checkURL", "url": "https://example.com/account", }
Selon le service, ils peuvent vous rediriger du tableau de bord vers la page de connexion si vous n'êtes pas authentifié. Dans ce cas, vous pouvez utiliser l'étape checkURL
pour vérifier si l'URL correspond toujours après avoir visité le tableau de bord.
{ "action": "navigate", "url": "https://example.com/dashboard"}, { "action": "checkURL", "url": "https://example.com/dashboard", }
Notez que vous pouvez utiliser des modèles globaux pour faire correspondre les URL dynamiques : https://example.com/dashboard/**
.
Vous pouvez utiliser un sélecteur unique à l'état authentifié pour vérifier si l'utilisateur est authentifié, par exemple un bouton de déconnexion ou un lien de profil.
{ "action": "navigate", "url": "https://example.com/home"}, { "action": "waitForElement", "selector": "#logout-button"}
Dans certains cas, le site Web n'est pas complètement chargé lorsque l'étape checkElementExists
est exécutée. Pour éviter cela, vous pouvez utiliser l'attribut waitForNetworkIdle
pour attendre que la page soit complètement chargée.
{ "action": "navigate", "url": "https://example.com/home", "waitForNetworkIdle": true}, { "action": "checkElementExists", "selector": "#logout-button"}
startAuth
)La plupart des processus d'authentification commencent par accéder à la page de connexion et attendre qu'un élément spécifique apparaisse après une connexion réussie.
N'oubliez pas que le navigateur sera visible pendant le processus d'authentification, permettant à l'utilisateur d'interagir avec le formulaire de connexion. Le flux d’authentification lui-même peut être automatisé, mais n’est pas obligatoire.
{ "action": "navigate", "url": "https://example.com/login"}, { "action": "waitForElement", "selector": "#logout-button", "timeout": 120000}
Pour donner à l'utilisateur suffisamment de temps pour se connecter, il est recommandé de prévoir un délai d'attente long pour l'étape d'attente, avec une valeur par défaut de 120 secondes.
Cette section donne un aperçu des étapes disponibles qui peuvent être utilisées pour créer des plugins pour Invoice Radar. Chaque étape représente une action spécifique qui peut être effectuée pendant le processus d'automatisation.
Étapes de navigation
Naviguer ( navigate
)
Attendre l'URL ( waitForURL
)
Attendre l'élément ( waitForElement
)
Attendre la navigation ( waitForNavigation
)
Attendez l'inactivité du réseau ( waitForNetworkIdle
)
Étapes d'interaction
Cliquez sur Élément ( click
)
Tapez du texte ( type
)
Sélectionnez la liste déroulante ( dropdownSelect
)
Exécutez JavaScript ( runJs
)
Étapes de vérification
Vérifier que l'élément existe ( checkElementExists
)
Vérifier l'URL ( checkURL
)
Exécutez JavaScript ( runJs
)
Étapes d'extraction de données
Extraire ( extract
)
Extraire tout ( extractAll
)
Étapes de récupération de documents
Télécharger le PDF ( downloadPdf
)
Attendez le téléchargement du PDF ( waitForPdfDownload
)
Imprimer la page au format PDF ( printPdf
)
Télécharger le PDF Base64 ( downloadBase64Pdf
)
Étapes logiques conditionnelles
Si ( if
)
Étapes diverses
Dormir ( sleep
)
Extraits
Obtenir la facture à partir de l'URL Stripe ( getInvoiceFromStripeUrl
)
Obtenez des factures à partir du portail client Stripe ( getInvoicesFromStripeBillingPortal
)
navigate
)Navigue vers l'URL donnée et attend que la page se charge. Par défaut, il attend uniquement le chargement initial de la page, pas les requêtes AJAX ultérieures.
{ "action": "navigate", "url": "https://example.com"}
Vous pouvez définir waitForNetworkIdle
sur true
pour vous assurer que la page est entièrement chargée avant de continuer.
{ "action": "navigate", "url": "https://example.com/dashboard", "waitForNetworkIdle": true}
Bon à savoir :
Les URL relatives sont prises en charge et seront résolues en fonction de la page actuelle.
L'action de navigation attendra uniquement le chargement initial de la page, pas les requêtes AJAX ultérieures.
waitForURL
)Attend que l'URL actuelle corresponde à l'URL donnée, éventuellement avec un délai d'attente. Prend en charge les caractères génériques.
{ "action": "waitForURL", "url": "https://example.com/profile/**", "timeout": 3000}
waitForElement
)Attend que le sélecteur donné apparaisse sur la page, éventuellement avec un délai d'attente.
{ "action": "waitForElement", "selector": "#example", "timeout": 3000}
waitForNavigation
)Attend que la navigation dans la page ait lieu. Cette étape n'attendra pas que la page soit complètement chargée. Utilisez l’étape waitForNetworkIdle à cette fin. Le délai d'attente est facultatif et est par défaut de 10 secondes
{ "action": "waitForNavigation", "timeout": 10000}
waitForNetworkIdle
)Attend que le réseau soit inactif. Ceci est utile si vous souhaitez vous assurer que la page a fini de charger toutes les ressources. Les étapes se terminent lorsqu'il n'y a plus de requêtes réseau pendant 500 ms. Le délai d'attente est facultatif et est par défaut de 15 secondes.
L'étape navigate
comporte une option waitForNetworkIdle
qui peut être définie sur true
pour obtenir le même comportement.
{ "action": "waitForNetworkIdle", "timeout": 10000}
click
)Clique sur l'élément spécifié par le sélecteur donné sur la page.
{ "action": "clic", "sélecteur": "#bouton"}
type
)Tape le texte donné dans l'élément spécifié par le sélecteur donné sur la page.
{ "action": "type", "selector": "#input", "value": "Hello World"}
dropdownSelect
) Sélectionne la valeur donnée dans la liste déroulante spécifiée par le sélecteur donné sur la page. La sélection s'effectue en fonction de l'attribut value
de l'option.
{ "action": "dropdownSelect", "selector": "#dropdown", "value": "Option 1"}
runJs
)Exécute le JavaScript donné dans le contexte de la page. Si une promesse est rendue, elle sera attendue.
Si vous souhaitez utiliser le résultat d'un script dans les étapes suivantes, utilisez plutôt l'étape d'extraction.
{ "action": "runJs", "script": "document.querySelector('#example').click();"}
Ces étapes sont utilisées dans checkAuth
pour vérifier si l'utilisateur est authentifié.
checkElementExists
)Vérifie si le sélecteur donné existe sur la page. Généralement utilisé pour les contrôles d'authentification.
{ "action": "checkElementExists", "selector": "#example"}
checkURL
) Vérifie si l'URL actuelle correspond à l'URL donnée. Prend en charge les modèles de caractères génériques tels que https://example.com/dashboard/**
.
{ "action": "checkURL", "url": "https://example.com"}
runJs
) L'étape runJs
peut également être utilisée comme étape de vérification. En exécutant un script qui renvoie une valeur véridique ou fausse, vous pouvez vérifier si l'utilisateur est authentifié.
{ "action": "runJs", "script": "document.cookie.includes('authToken');"}
Ces étapes sont utilisées pour charger des données de la page, comme une liste d'éléments ou une valeur unique, et les utiliser dans les étapes suivantes.
extract
)Extrait une seule donnée de la page et la stocke dans une variable.
Utilisation d'un champ CSS :
{ "action": "extract", "variable": "account", "fields": { "id": "#team-id", "name": "#team-name", "url": { " selector": "#team-link", "attribute": "href" } } }
Dans cet exemple, account
est utilisé comme nom de variable et les champs id
, name
et url
sont extraits à l'aide de sélecteurs CSS. Ils peuvent être utilisés dans les étapes suivantes à l'aide des espaces réservés {{account.id}}
, {{account.name}}
et {{account.url}}
.
Utilisation de JavaScript :
{ "action": "extract", "variable": "token", "script": "localStorage.getItem('authToken')"}
Cet exemple crée une variable token
extraite à l'aide de JavaScript. La valeur est accessible à l'aide de l'espace réservé {{token}}
. Il est également possible de restituer un objet.
extractAll
)Extrait une liste de données de la page et exécute les étapes indiquées pour chaque élément. Ceci est couramment utilisé pour parcourir une liste de factures et les télécharger.
Pour chaque élément correspondant au selector
, les champs sont extraits et stockés dans la variable
disponible dans les étapes forEach
.
Bon à savoir :
Chaque sélecteur à l’intérieur de l’objet fields
est automatiquement limité à l’élément correspondant.
Le champ variable
est facultatif. Si elles ne sont pas fournies, les données extraites seront stockées dans l' item
variable par défaut.
L'index actuel est accessible à l'aide de l'espace réservé {{index}}
. Il commence à 0 et s'incrémente pour chaque élément.
Avec les champs CSS :
{ "action": "extractAll", "selector": ".invoice-list .invoice-item", "variable": "invoice", "fields": { "id": "td.invoice-id", " date": "td.invoice-date", "total": "td.invoice-total", "url": { "selector": "a.invoice-link", "attribute": "href" } }, "pourChaque": [ { "action": "navigate", "url": "{{invoice.url}}" }, { "action": "downloadPdf", "invoice": "{{invoice}}" } ] }
Avec Javascript :
Lorsque vous utilisez JavaScript, le résultat doit être un tableau d'objets ou de valeurs. Si le résultat est une promesse, il sera attendu.
{ "action": "extractAll", "script": "Array.from(document.querySelectorAll('#year-selector option')).map(option => option.value);", "variable": "année ", "pourChaque": [ { "action": "dropdownSelect", "selector": "#year-selector", "value": "{{year}}" } ] }
Pagination
Support expérimental, non encore documenté.
Ces étapes permettent de télécharger des documents et de les traiter dans Invoice Radar. Toutes les étapes nécessitent que l'objet document
soit passé en argument, qui contient les métadonnées du document.
L'argument document
comporte les champs suivants :
Requis
id
: l'identifiant unique du document
Par exemple INV-123
ou 123456
date
: La date de la facture sous forme de chaîne
Par exemple 2022-01-01
ou 01/01/2022
ou January 1, 2022
Recommandé
total
: Le montant total de la facture incluant la devise.
Par exemple $100.00
ou €100.00
ou 100 EUR
ou 100,00€
L'analyseur intégré tentera d'extraire le montant et la devise de la chaîne.
Facultatif
type
: Le type du document (Facultatif. La valeur par défaut est auto
)
Peut être réglé sur auto
, invoice
, receipt
, refund
ou other
.
metadata
: Métadonnées supplémentaires pour le document (Facultatif)
Par exemple { "orderNumber": "12345" }
Vous pouvez soit transmettre chaque champ séparément, soit l'objet entier s'il contient tous les champs obligatoires.
Par exemple, en utilisant des champs séparés :
"document": { "id": "{{item.invoiceId}}", "date": "{{item.date}}", "total": "{{item.amount}} {{item.currency }}", "type": "facture"}
Par exemple, si l'objet contient tous les champs obligatoires, vous pouvez le transmettre directement :
"document": "{{élément}}"
downloadPdf
)Télécharge un PDF à partir de l'URL indiquée.
{ "action": "downloadPdf", "url": "https://example.com/invoice.pdf", "document": { "id": "{{item.invoiceId}}", "date": "{{item.date}}", "total": "{{item.total}}" } }
waitForPdfDownload
)Attend un téléchargement PDF. Le délai d'expiration est par défaut de 15 secondes.
{ "action": "waitForPdfDownload", "timeout": 10000, "document": { "id": "{{item.invoiceId}}", "date": "{{item.date}}", "total ": "{{item.total}}" } }
printPdf
)Imprime la page actuelle dans un fichier PDF.
{ "action": "printPdf", "document": { "id": "{{item.invoiceId}}", "date": "{{item.date}}", "total": "{{item .total}}" } }
downloadBase64Pdf
)Télécharge un PDF à partir d’une chaîne codée en base64.
{ "action": "downloadBase64Pdf", "base64": "{{item.base64String}}", "document": { "id": "{{item.invoiceId}}", "date": "{{item .date}}", "total": "{{item.total}}" } }
if
) Exécute les étapes indiquées si la condition est vraie. Si la condition est fausse, les étapes else
sont exécutées.
{ "action": "if", "script": "'{{invoice.url}}'.includes('pdf')", "then": [ { "action": "clic", "sélecteur": "#exemple" } ], "autre": [ { "action": "navigate", "url": "https://example.com/fallback" } ] }
sleep
)Attend la durée donnée en millisecondes. Ceci n’est généralement pas recommandé. Dans la plupart des cas, il est préférable d'utiliser les étapes waitForElement, waitForURL ou waitForNetworkIdle.
{ "action": "sommeil", "durée": 1000}
Les extraits de code sont des ensembles d'étapes prédéfinis qui simplifient les tâches courantes. Les étapes d'un extrait spécifique sont visibles dans les outils de développement
Actuellement, il n'est pas possible de créer des extraits personnalisés. Si vous avez une tâche courante qui, selon vous, serait utile sous forme d'extrait, veuillez créer un problème sur GitHub.
getInvoiceFromStripeUrl
)Extrait une facture à partir d'une URL de facture Stripe.
{ "action": "runSnippet", "snippet": "getInvoiceFromStripeUrl", "args": { "url": "https://invoice.stripe.com/i/inv_123" } }
getInvoicesFromStripeBillingPortal
)Extrait les factures disponibles d'un portail de facturation Stripe.
{ "action": "runSnippet", "snippet": "getInvoicesFromStripeBillingPortal", "args": { "url": "https://stripe-portal.example.com/billing" } }
Parfois, vous devrez peut-être exécuter une requête d'extraction au cours d'une étape pour récupérer des données à partir d'une API. Pour ce faire, vous pouvez utiliser l'action extractAll
.
{ "action": "extractAll", "variable": "invoice", "script": "fetch('https://example.com/api/invoices').then(res => res.json()) " "pourChacun": [ { "action": "downloadPdf", "url": "{{invoice.url}}", "document": { "id": "{{invoice.id}}", "date": "{{invoice .date}}", "total": "{{invoice.total}}" } } ] }
Cela exécutera la demande de récupération et renverra le résultat sous forme d'objet JavaScript.
<iframe/>
Dans certains scénarios, vous devrez peut-être exécuter une étape dans un élément <iframe/>
. Pour ce faire, vous pouvez utiliser l'attribut iframe
sur l'étape.
{ "action": "click", "selector": "#button-inside-iframe", "iframe": true},
En définissant iframe
sur true
, Invoice Radar trouvera le premier élément <iframe/>
de la page et exécutera l'étape à l'intérieur.
Vous pouvez également utiliser une chaîne contenue dans l'attribut src
de l'iframe pour cibler une iframe spécifique.
{ "action": "click", "selector": "#button-inside-iframe", "iframe": "iframe.example.com"},