1. Présentation
Dans cet atelier de programmation, vous allez utiliser Google Apps Script pour écrire un module complémentaire Google Workspace pour Gmail qui permettra aux utilisateurs d'ajouter les données de reçus d'un e-mail à une feuille de calcul directement dans Gmail. Lorsqu'un utilisateur reçoit un reçu par e-mail, il ouvre le module complémentaire qui reçoit automatiquement les informations de dépenses pertinentes. L'utilisateur peut modifier les informations relatives aux dépenses, puis les envoyer pour consigner les dépenses dans une feuille de calcul Google Sheets.
Points abordés
- Créer un module complémentaire Google Workspace pour Gmail à l'aide de Google Apps Script
- Analyser un e-mail avec Google Apps Script
- Interaction avec Google Sheets via Google Apps Script
- Stocker les valeurs utilisateur à l'aide du service Propriétés du script Google Apps
Prérequis
- Accès à Internet et à un navigateur Web
- Un compte Google
- Certains messages, de préférence des reçus, dans Gmail
2. Obtenir l'exemple de code
Au fur et à mesure que vous progressez dans cet atelier de programmation, il peut être utile de référencer une version fonctionnelle du code que vous allez écrire. Le dépôt GitHub contient un exemple de code que vous pouvez utiliser comme référence.
Pour obtenir l'exemple de code, exécutez la commande suivante à partir de la ligne de commande:
git clone https://github.com/googleworkspace/gmail-add-on-codelab.git
3. Créer un module complémentaire de base
Commencez par écrire le code d'une version simple du module complémentaire qui affiche un formulaire de dépenses à côté d'un e-mail.
Commencez par créer un projet Apps Script et ouvrez son fichier manifeste.
- Accédez à script.google.com. Vous pouvez alors créer, gérer et surveiller vos projets Apps Script.
- Pour créer un projet, cliquez sur Nouveau projet en haut à gauche. Le nouveau projet s'ouvre avec un fichier par défaut nommé
Code.gs
. LaissezCode.gs
de côté pour le moment, vous vous en occuperez plus tard. - Cliquez sur Projet sans titre, nommez votre projet Expense It!, puis cliquez sur Renommer.
- Sur la gauche, cliquez sur Paramètres du projet .
- Cochez la case Afficher "appscript.json" manifeste dans l'éditeur".
- Cliquez sur Éditeur.
- Pour ouvrir le fichier manifeste, cliquez sur
appscript.json
à gauche.
Dans appscript.json
, spécifiez les métadonnées associées au module complémentaire, telles que son nom et les autorisations requises. Remplacez le contenu de appsscript.json
par les paramètres de configuration suivants:
{
"timeZone": "GMT",
"oauthScopes": [
"https://www.googleapis.com/auth/gmail.addons.execute"
],
"gmail": {
"name": "Expense It!",
"logoUrl": "https://www.gstatic.com/images/icons/material/system/1x/receipt_black_24dp.png",
"contextualTriggers": [{
"unconditional": {
},
"onTriggerFunction": "getContextualAddOn"
}],
"primaryColor": "#41f470",
"secondaryColor": "#94f441"
}
}
Portez une attention particulière à la partie du fichier manifeste appelée contextualTriggers
. Cette partie du fichier manifeste identifie la fonction définie par l'utilisateur à appeler lorsque le module complémentaire est activé pour la première fois. Dans ce cas, il appelle getContextualAddOn
, qui récupère des informations sur l'e-mail ouvert et renvoie un ensemble de fiches à présenter à l'utilisateur.
Pour créer la fonction getContextualAddOn
, procédez comme suit:
- À gauche, pointez sur
Code.gs
, puis cliquez sur Menu > Renommer. - Saisissez
GetContextualAddOn
, puis appuyez sur la toucheEnter
. Apps Script ajoute automatiquement.gs
au nom de votre fichier. Vous n'avez donc pas besoin de saisir une extension de fichier. Si vous saisissezGetContextualAddOn.gs
, Apps Script nomme votre fichierGetContextualAddOn.gs.gs
. - Dans
GetContextualAddOn.gs
, remplacez le code par défaut par la fonctiongetContextualAddOn
:
/**
* Returns the contextual add-on data that should be rendered for
* the current e-mail thread. This function satisfies the requirements of
* an 'onTriggerFunction' and is specified in the add-on's manifest.
*
* @param {Object} event Event containing the message ID and other context.
* @returns {Card[]}
*/
function getContextualAddOn(event) {
var card = CardService.newCardBuilder();
card.setHeader(CardService.newCardHeader().setTitle('Log Your Expense'));
var section = CardService.newCardSection();
section.addWidget(CardService.newTextInput()
.setFieldName('Date')
.setTitle('Date'));
section.addWidget(CardService.newTextInput()
.setFieldName('Amount')
.setTitle('Amount'));
section.addWidget(CardService.newTextInput()
.setFieldName('Description')
.setTitle('Description'));
section.addWidget(CardService.newTextInput()
.setFieldName('Spreadsheet URL')
.setTitle('Spreadsheet URL'));
card.addSection(section);
return [card.build()];
}
L'interface utilisateur de chaque module complémentaire Google Workspace se compose de fiches divisées en une ou plusieurs sections, chacune contenant des widgets pouvant afficher des informations et obtenir des informations de l'utilisateur. La fonction getContextualAddOn
crée une seule carte qui reçoit les détails d'une dépense trouvée dans un e-mail. La fiche comporte une section contenant des champs de saisie de texte pour les données pertinentes. La fonction renvoie un tableau des cartes du module complémentaire. Dans ce cas, le tableau renvoyé ne comprend qu'une seule fiche.
Avant de déployer la solution Expense It! vous avez besoin d'un projet Google Cloud Platform (GCP), que les projets Apps Script utilisent pour gérer les autorisations, les services avancés et d'autres informations. Pour en savoir plus, consultez la page Projets Google Cloud Platform.
Pour déployer et exécuter votre module complémentaire, procédez comme suit:
- Ouvrez votre projet GCP et copiez son numéro de projet.
- À gauche de votre projet Apps Script, cliquez sur Paramètres du projet .
- Sous "Projet Google Cloud Platform (GCP)", cliquez sur Changer de projet.
- Saisissez le numéro de votre projet GCP, puis cliquez sur Définir le projet.
- Cliquez sur Déployer > Tester les déploiements.
- Assurez-vous que le type de déploiement correspond à Module complémentaire Google Workspace. Si nécessaire, en haut de la boîte de dialogue, cliquez sur Activer les types de déploiement , puis sélectionnez Module complémentaire Google Workspace comme type de déploiement.
- À côté de Application(s): Gmail, cliquez sur Installer.
- Cliquez sur OK.
Ce module complémentaire apparaît désormais dans votre boîte de réception Gmail.
- Ouvrez Gmail sur votre ordinateur.
- Sur le panneau de droite, la section "Expense It!" Le module complémentaire s'affiche. Vous devrez peut-être cliquer sur Plus de modules complémentaires pour le trouver.
- Ouvrez un e-mail, de préférence un reçu indiquant vos dépenses.
- Pour ouvrir le module complémentaire, cliquez sur "Expense It" (Dépenser) dans le panneau latéral droit. .
- Dépensez-le ! l'accès à votre compte Google. Pour ce faire, cliquez sur Autoriser l'accès, puis suivez les instructions qui s'affichent.
Le module complémentaire affiche un formulaire simple à côté d'un message Gmail ouvert. Il ne fait rien d'autre pour l'instant, mais vous développerez ses fonctionnalités dans la section suivante.
Pour voir les mises à jour de votre module complémentaire au fur et à mesure de cet atelier, il vous suffit d'enregistrer votre code et d'actualiser Gmail. Aucun déploiement supplémentaire n'est nécessaire.
4. Accéder aux e-mails
Ajoutez du code qui extrait le contenu des e-mails et le modularise pour renforcer l'organisation.
À côté de "Fichiers", cliquez sur Ajouter > Script, puis créez un fichier nommé Cards
. Créez un deuxième fichier de script appelé Helpers
. Cards.gs
crée la fiche et utilise les fonctions de Helpers.gs
pour remplir les champs du formulaire en fonction du contenu de l'e-mail.
Remplacez le code par défaut dans Cards.gs
par le code suivant:
var FIELDNAMES = ['Date', 'Amount', 'Description', 'Spreadsheet URL'];
/**
* Creates the main card users see with form inputs to log expenses.
* Form can be prefilled with values.
*
* @param {String[]} opt_prefills Default values for each input field.
* @param {String} opt_status Optional status displayed at top of card.
* @returns {Card}
*/
function createExpensesCard(opt_prefills, opt_status) {
var card = CardService.newCardBuilder();
card.setHeader(CardService.newCardHeader().setTitle('Log Your Expense'));
if (opt_status) {
if (opt_status.indexOf('Error: ') == 0) {
opt_status = '<font color=\'#FF0000\'>' + opt_status + '</font>';
} else {
opt_status = '<font color=\'#228B22\'>' + opt_status + '</font>';
}
var statusSection = CardService.newCardSection();
statusSection.addWidget(CardService.newTextParagraph()
.setText('<b>' + opt_status + '</b>'));
card.addSection(statusSection);
}
var formSection = createFormSection(CardService.newCardSection(),
FIELDNAMES, opt_prefills);
card.addSection(formSection);
return card;
}
/**
* Creates form section to be displayed on card.
*
* @param {CardSection} section The card section to which form items are added.
* @param {String[]} inputNames Names of titles for each input field.
* @param {String[]} opt_prefills Default values for each input field.
* @returns {CardSection}
*/
function createFormSection(section, inputNames, opt_prefills) {
for (var i = 0; i < inputNames.length; i++) {
var widget = CardService.newTextInput()
.setFieldName(inputNames[i])
.setTitle(inputNames[i]);
if (opt_prefills && opt_prefills[i]) {
widget.setValue(opt_prefills[i]);
}
section.addWidget(widget);
}
return section;
}
La fonction createExpensesCard
utilise un tableau de valeurs pour préremplir le formulaire en tant qu'argument facultatif. La fonction peut afficher un message d'état facultatif, d'une couleur rouge si l'état commence par "Erreur :", et sinon vert. Au lieu d'ajouter manuellement chaque champ au formulaire, une fonction d'assistance appelée createFormSection
parcourt le processus de création de widgets de saisie de texte, définit chaque valeur par défaut avec setValue
, puis ajoute les widgets à leurs sections respectives sur la fiche.
Remplacez maintenant le code par défaut dans Helpers.gs
par le code suivant:
/**
* Finds largest dollar amount from email body.
* Returns null if no dollar amount is found.
*
* @param {Message} message An email message.
* @returns {String}
*/
function getLargestAmount(message) {
return 'TODO';
}
/**
* Determines date the email was received.
*
* @param {Message} message An email message.
* @returns {String}
*/
function getReceivedDate(message) {
return 'TODO';
}
/**
* Determines expense description by joining sender name and message subject.
*
* @param {Message} message An email message.
* @returns {String}
*/
function getExpenseDescription(message) {
return 'TODO';
}
/**
* Determines most recent spreadsheet URL.
* Returns null if no URL was previously submitted.
*
* @returns {String}
*/
function getSheetUrl() {
return 'TODO';
}
Les fonctions de Helpers.gs
sont appelées par getContextualAddon
pour déterminer les valeurs préremplies dans le formulaire. Pour le moment, ces fonctions ne renvoient que la chaîne "TODO" car vous implémenterez la logique de préremplissage lors d'une prochaine étape.
Ensuite, mettez à jour le code dans GetContextualAddon.gs
afin qu'il exploite le code de Cards.gs
et Helpers.gs
. Remplacez le code dans GetContextualAddon.gs
par le code suivant:
/**
* Copyright 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Returns the contextual add-on data that should be rendered for
* the current e-mail thread. This function satisfies the requirements of
* an 'onTriggerFunction' and is specified in the add-on's manifest.
*
* @param {Object} event Event containing the message ID and other context.
* @returns {Card[]}
*/
function getContextualAddOn(event) {
var message = getCurrentMessage(event);
var prefills = [getReceivedDate(message),
getLargestAmount(message),
getExpenseDescription(message),
getSheetUrl()];
var card = createExpensesCard(prefills);
return [card.build()];
}
/**
* Retrieves the current message given an action event object.
* @param {Event} event Action event object
* @return {Message}
*/
function getCurrentMessage(event) {
var accessToken = event.messageMetadata.accessToken;
var messageId = event.messageMetadata.messageId;
GmailApp.setCurrentMessageAccessToken(accessToken);
return GmailApp.getMessageById(messageId);
}
Notez la nouvelle fonction getCurrentMessage
, qui utilise l'événement fourni par Gmail pour lire le message actuellement ouvert de l'utilisateur. Pour que cette fonction fonctionne, ajoutez au fichier manifeste du script un champ d'application supplémentaire qui autorise un accès en lecture seule aux messages Gmail.
Dans appscript.json
, mettez à jour oauthScopes
afin qu'il demande également le champ d'application https://www.googleapis.com/auth/gmail.addons.current.message.readonly
.
"oauthScopes": [
"https://www.googleapis.com/auth/gmail.addons.execute",
"https://www.googleapis.com/auth/gmail.addons.current.message.readonly"
],
Dans Gmail, exécutez votre module complémentaire et autorisez l'accès pour Expense It! pour afficher les e-mails. Les champs du formulaire sont désormais préremplis avec la mention "TODO".
5. Interagir avec Google Sheets
Dépensez-vous ! Le module complémentaire propose un formulaire permettant à l'utilisateur de saisir les détails d'une dépense, mais ces informations n'ont nulle part où aller. Ajoutons un bouton qui envoie les données du formulaire vers une feuille de calcul Google Sheets.
Pour ajouter un bouton, nous utiliserons la classe ButtonSet. Pour gérer l'interface avec Google Sheets, vous devez utiliser le service Google Sheets.
Modifiez createFormSection
pour renvoyer un bouton intitulé "Submit" (Envoyer). dans la section "Formulaire" de la fiche. Suivez les instructions suivantes :
- Créez un bouton textuel à l'aide de
CardService.newTextButton()
, avec l'étiquette "Envoyer". avecCardService.TextButton.setText()
. - Concevez le bouton de sorte que lorsqu'un utilisateur clique dessus, l'action
submitForm
suivante est appelée viaCardService.TextButton.setOnClickAction()
:
/**
* Logs form inputs into a spreadsheet given by URL from form.
* Then displays edit card.
*
* @param {Event} e An event object containing form inputs and parameters.
* @returns {Card}
*/
function submitForm(e) {
var res = e['formInput'];
try {
FIELDNAMES.forEach(function(fieldName) {
if (! res[fieldName]) {
throw 'incomplete form';
}
});
var sheet = SpreadsheetApp
.openByUrl((res['Spreadsheet URL']))
.getActiveSheet();
sheet.appendRow(objToArray(res, FIELDNAMES.slice(0, FIELDNAMES.length - 1)));
return createExpensesCard(null, 'Logged expense successfully!').build();
}
catch (err) {
if (err == 'Exception: Invalid argument: url') {
err = 'Invalid URL';
res['Spreadsheet URL'] = null;
}
return createExpensesCard(objToArray(res, FIELDNAMES), 'Error: ' + err).build();
}
}
/**
* Returns an array corresponding to the given object and desired ordering of keys.
*
* @param {Object} obj Object whose values will be returned as an array.
* @param {String[]} keys An array of key names in the desired order.
* @returns {Object[]}
*/
function objToArray(obj, keys) {
return keys.map(function(key) {
return obj[key];
});
}
- Créez un widget d'ensemble de boutons à l'aide de
CardService.newButtonSet()
et ajoutez votre bouton textuel au jeu de boutons avecCardService.ButtonSet.addButton()
. - Ajoutez le widget d'ensemble de boutons à la section "Formulaire" de la fiche à l'aide de
CardService.CardSection.addWidget()
.
Avec quelques lignes de code, nous pouvons ouvrir une feuille de calcul à l'aide de son URL, puis y ajouter une ligne de données. Notez que les entrées du formulaire sont transmises à la fonction dans le cadre de l'événement e
. Nous vérifions alors que l'utilisateur a fourni tous les champs. Si aucune erreur ne se produit, nous créons une fiche de dépenses vide avec un état favorable. Si nous détectons une erreur, nous renvoyons la carte remplie d'origine avec le message d'erreur. La fonction d'assistance objToArray
facilite la conversion des réponses au formulaire en un tableau, qui peut ensuite être ajouté à la feuille de calcul.
Enfin, mettez à jour la section oauthScopes
dans appsscript.json
et demandez à nouveau le champ d'application https://www.googleapis.com/auth/spreadsheets
. Lorsqu'il est autorisé, ce champ d'application permet au module complémentaire de lire et de modifier les feuilles de calcul Google Sheets d'un utilisateur.
"oauthScopes": [
"https://www.googleapis.com/auth/gmail.addons.execute",
"https://www.googleapis.com/auth/gmail.addons.current.message.readonly",
"https://www.googleapis.com/auth/spreadsheets"
],
Si vous n'avez pas encore créé de feuille de calcul, créez-en une sur https://docs.google.com/spreadsheets/.
Exécutez à nouveau le module complémentaire et essayez d'envoyer le formulaire. Veillez à saisir l'URL complète de votre URL de destination dans le champ URL de la feuille de calcul du formulaire.
6. Stocker des valeurs avec le service Propriétés
Souvent, les utilisateurs enregistrent de nombreuses dépenses dans la même feuille de calcul. Il est donc pratique d'offrir l'URL la plus récente de la feuille de calcul comme valeur par défaut dans la carte. Pour connaître l'URL de la feuille de calcul la plus récente, nous devons stocker cette information chaque fois que le module complémentaire est utilisé.
Le service Propriétés nous permet de stocker des paires clé/valeur. Dans notre cas, la clé "SPREADSHEET_URL" peut être raisonnable. tandis que la valeur est l'URL elle-même. Pour stocker une telle valeur, vous devez modifier submitForm
dans Cards.gs
de sorte que l'URL de la feuille de calcul soit stockée en tant que propriété lors de l'ajout d'une nouvelle ligne à la feuille.
Notez que les propriétés peuvent avoir l'un des trois champs d'application suivants: script, utilisateur ou document. Le champ d'application Document ne s'applique pas aux modules complémentaires Gmail, bien qu'il concerne un type de module complémentaire distinct pour le stockage d'informations spécifiques à un document Google Docs ou une feuille de calcul Google Sheets spécifique. Dans le cas de notre module complémentaire, nous souhaitons que les utilisateurs voient leur feuille de calcul la plus récente (et non celle d'une autre personne) comme option par défaut dans le formulaire. Par conséquent, nous sélectionnons le champ d'application user au lieu de script.
Utilisez PropertiesService.getUserProperties().setProperty()
pour stocker l'URL de la feuille de calcul. Ajoutez le code suivant à submitForm
dans Cards.gs
:
PropertiesService.getUserProperties().setProperty('SPREADSHEET_URL',
res['Spreadsheet URL']);
Modifiez ensuite la fonction getSheetUrl
dans Helpers.gs
pour renvoyer la propriété stockée afin que l'utilisateur voie l'URL la plus récente chaque fois qu'il utilise le module complémentaire. Utilisez PropertiesService.getUserProperties().getProperty()
pour obtenir la valeur de la propriété.
/**
* Determines most recent spreadsheet URL.
* Returns null if no URL was previously submitted.
*
* @returns {String}
*/
function getSheetUrl() {
return PropertiesService.getUserProperties().getProperty('SPREADSHEET_URL');
}
Enfin, pour accéder au service Property, le script doit également être autorisé. Comme précédemment, ajoutez le champ d'application https://www.googleapis.com/auth/script.storage
au fichier manifeste pour permettre à votre module complémentaire de lire et d'écrire des informations sur la propriété.
7. Analyser le message Gmail
Pour faire vraiment économiser
aux utilisateurs préremplissons le formulaire avec les informations
pertinentes sur la dépense de l'e-mail. Nous avons déjà créé des fonctions dans Helpers.gs
qui jouent ce rôle, mais pour l'instant, nous n'avons renvoyé que "TODO" pour connaître la date, le montant et la description de la dépense.
Par exemple, nous pouvons obtenir la date de réception de l'e-mail et l'utiliser comme valeur par défaut pour la date de la dépense.
/**
* Determines date the email was received.
*
* @param {Message} message - The message currently open.
* @returns {String}
*/
function getReceivedDate(message) {
return message.getDate().toLocaleDateString();
}
Implémentez les deux autres fonctions:
getExpenseDescription
peut impliquer de joindre à la fois le nom de l'expéditeur et l'objet du message, bien qu'il existe des moyens plus sophistiqués d'analyser le corps du message et d'en fournir une description encore plus précise.- Pour
getLargestAmount
, recherchez des symboles spécifiques associés à l'argent. Les reçus comportent souvent plusieurs valeurs, telles que les taxes et d'autres frais. Pensez à la façon dont vous pourriez identifier le bon montant. Les expressions régulières peuvent également être utiles.
Si vous avez besoin d'inspiration, consultez la documentation de référence sur GmailMessage
ou consultez le code de solution que vous avez téléchargé au début de l'atelier de programmation. Une fois que vous avez conçu vos propres implémentations pour toutes les fonctions de Helpers.gs
, essayez votre module complémentaire. Ouvrez les reçus et enregistrez-les dans une feuille de calcul.
8. Effacer le formulaire avec des actions liées aux fiches
Que se passe-t-il en cas d'attaque par dépenses ? mal identifié une dépense dans un e-mail ouvert et préremplit le formulaire avec des informations incorrectes ? L'utilisateur efface le formulaire. La classe CardAction permet de spécifier une fonction qui est appelée lorsque l'utilisateur clique sur l'action. Utilisons-le pour donner à l’utilisateur un moyen rapide d’effacer le formulaire.
Modifiez createExpensesCard
de sorte que la carte renvoyée comporte une action de carte intitulée "Effacer le formulaire". Lorsque vous cliquez dessus, la fonction clearForm
suivante est appelée, que vous pouvez coller dans Cards.gs
. Vous devez transmettre opt_status
en tant que paramètre nommé "Status" (État). à l'action pour s'assurer que le message d'état reste affiché une fois le formulaire effacé. Notez que les paramètres facultatifs des actions doivent être du type Object.<string, string>. Par conséquent, si opt_status
n'est pas disponible, vous devez transmettre {'Status' : ''}
.
/**
* Recreates the main card without prefilled data.
*
* @param {Event} e An event object containing form inputs and parameters.
* @returns {Card}
*/
function clearForm(e) {
return createExpensesCard(null, e['parameters']['Status']).build();
}
9. Créer une feuille de calcul
En plus d'utiliser Google Apps Script pour modifier une feuille de calcul existante, vous pouvez en créer une par programmation. Pour notre module complémentaire, permettons à l'utilisateur de créer une feuille de calcul pour les dépenses. Pour commencer, ajoutez la section suivante à la fiche renvoyée par createExpensesCard
.
var newSheetSection = CardService.newCardSection();
var sheetName = CardService.newTextInput()
.setFieldName('Sheet Name')
.setTitle('Sheet Name');
var createExpensesSheet = CardService.newAction()
.setFunctionName('createExpensesSheet');
var newSheetButton = CardService.newTextButton()
.setText('New Sheet')
.setOnClickAction(createExpensesSheet);
newSheetSection.addWidget(sheetName);
newSheetSection.addWidget(CardService.newButtonSet().addButton(newSheetButton));
card.addSection(newSheetSection);
Maintenant, lorsque l'utilisateur clique
sur la « Nouvelle feuille », le module complémentaire génère une nouvelle feuille de calcul mise en forme avec une ligne d'en-tête figée afin qu'elle soit toujours visible. L'utilisateur spécifie un titre pour la nouvelle feuille de calcul dans le formulaire, bien qu'inclure une valeur par défaut si le formulaire est vide pourrait être un bon choix. Dans votre implémentation de createExpensesSheet
, renvoyez une fiche presque identique à la fiche existante, en ajoutant un message d'état approprié et en préremplissant le champ d'URL avec l'URL de la nouvelle feuille de calcul.
10. Félicitations !
Vous avez conçu et implémenté un module complémentaire Gmail qui détecte une dépense dans un e-mail et aide les utilisateurs à l'enregistrer dans une feuille de calcul en quelques secondes seulement. Vous avez utilisé Google Apps Script pour interagir avec plusieurs API Google et pour accéder à des données persistantes entre plusieurs exécutions du module complémentaire.
Améliorations possibles
Laissez votre imagination vous guider pour améliorer votre Dépense !, mais voici quelques idées pour créer un produit encore plus utile:
- Lien vers la feuille de calcul une fois que l'utilisateur a enregistré une dépense
- Possibilité de modifier ou d'annuler l'enregistrement d'une dépense
- Intégrez des API externes pour permettre aux utilisateurs d'effectuer des paiements et de demander de l'argent.