תוספים ל-Google Workspace מעודדים נקיטת פעולות בקלות באימייל

1. סקירה כללית

בשיעור ה-Codelab הזה משתמשים ב-Google Apps Script כדי לכתוב תוסף של Google Workspace ל-Gmail, שמאפשר למשתמשים להוסיף נתוני קבלות מאימייל לגיליון אלקטרוני ישירות ב-Gmail. כשמשתמש מקבל קבלה באימייל, הוא פותח את התוסף שמקבל אוטומטית מהאימייל מידע רלוונטי על ההוצאות. המשתמש יכול לערוך פרטי הוצאות ולאחר מכן לשלוח אותם כדי לרשום את ההוצאות בגיליון אלקטרוני של Google Sheets.

מה תלמדו

  • יצירת תוסף של Google Workspace ל-Gmail באמצעות Google Apps Script
  • ניתוח אימייל באמצעות Google Apps Script
  • אינטראקציה עם Google Sheets דרך Google Apps Script
  • אחסון ערכי משתמשים באמצעות שירות המאפיינים של Google Apps Script

למה תזדקק?

  • גישה לאינטרנט ולדפדפן אינטרנט
  • חשבון Google
  • הודעות מסוימות, רצוי באימיילים, ב-Gmail

2. לקבלת הקוד לדוגמה

במהלך העבודה ב-Codelab הזה, כדאי לעיין בגרסה תקינה של הקוד שתכתוב. מאגר ה-GitHub מכיל קוד לדוגמה שאפשר להשתמש בו כקובץ עזר.

כדי לקבל את הקוד לדוגמה, מריצים את הקוד משורת הפקודה:

git clone https://github.com/googleworkspace/gmail-add-on-codelab.git

3. יצירת תוסף בסיסי

קודם כל צריך לכתוב את הקוד לגרסה פשוטה של התוסף, שמציגה טופס הוצאות לצד האימייל.

קודם כול, יוצרים פרויקט Apps Script חדש ופותחים את קובץ המניפסט שלו.

  1. עוברים אל script.google.com. מכאן אפשר ליצור פרויקטים ב-Apps Script, לנהל אותם ולעקוב אחריהם.
  2. כדי ליצור פרויקט חדש, לוחצים על פרויקט חדש בפינה הימנית העליונה. הפרויקט החדש ייפתח עם קובץ ברירת מחדל בשם Code.gs. כרגע אפשר להשתמש ב-Code.gs בלי להשתמש במערכת ההפעלה שלו.
  3. לוחצים על Untitled project, נותנים שם לפרויקט Expense It! ולוחצים על Rename.
  4. בצד ימין, לוחצים על הגדרות הפרויקט הגדרות הפרויקט.
  5. בוחרים באפשרות הצגת "appscript.json" "קובץ מניפסט בעורך".
  6. לוחצים על עריכה עריכה.
  7. כדי לפתוח את קובץ המניפסט, לוחצים על appscript.json בצד ימין.

ב-appscript.json, מציינים את המטא-נתונים שמשויכים לתוסף, כמו השם שלו וההרשאות שהוא דורש. מחליפים את התוכן של appsscript.json בהגדרות האישיות הבאות:

{
  "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"
  }
}

חשוב במיוחד לשים לב לחלק של המניפסט שנקרא contextualTriggers. החלק הזה במניפסט מזהה את הפונקציה שהוגדרה על ידי המשתמש שצריך להפעיל כשמפעילים את התוסף בפעם הראשונה. במקרה כזה, הפונקציה מפעילה את הפונקציה getContextualAddOn, שמקבלת פרטים על האימייל הפתוח ומחזירה קבוצה של כרטיסים שיוצגו למשתמש.

כדי ליצור את הפונקציה getContextualAddOn, מבצעים את השלבים הבאים:

  1. בצד ימין, מחזיקים את הסמן מעל Code.gs, ואז לוחצים על 'תפריט' תפריט האפשרויות הנוספות > שינוי שם.
  2. מקלידים GetContextualAddOn ומקישים על המקש Enter. Apps Script מצרף את הסיומת .gs באופן אוטומטי לשם הקובץ, כך שלא צריך להקליד את סיומת הקובץ. אם מקלידים GetContextualAddOn.gs אז Apps Script נותן לקובץ את השם GetContextualAddOn.gs.gs.
  3. בפונקציה GetContextualAddOn.gs, מחליפים את קוד ברירת המחדל בפונקציה getContextualAddOn:
/**
 * 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()];
}

ממשק המשתמש של כל תוסף של Google Workspace מורכב מכרטיסים שמפוצלים לקטע אחד או יותר, וכל אחד מהם מכיל ווידג'טים שיכולים להציג ולקבל מידע מהמשתמש. הפונקציה getContextualAddOn יוצרת כרטיס יחיד שמקבל פרטים על הוצאה שנמצאה בהודעת אימייל. בכרטיס יש קטע אחד שמכיל שדות להזנת טקסט לנתונים רלוונטיים. הפונקציה מחזירה מערך של הכרטיסים של התוסף. במקרה הזה, המערך שיוחזר כולל רק כרטיס אחד.

לפני שמפעילים את Expense It! בתוסף נדרש פרויקט ב-Google Cloud Platform (GCP), שבו משתמשים בפרויקטים של Apps Script כדי לנהל הרשאות, שירותים מתקדמים ופרטים אחרים. למידע נוסף, ראו פרויקטים ב-Google Cloud Platform.

כדי לפרוס ולהפעיל את התוסף, צריך לבצע את הפעולות הבאות:

  1. פותחים את הפרויקט ב-GCP ומעתיקים את מספר הפרויקט.
  2. בפרויקט Apps Script, לוחצים על Project Settings (הגדרות הפרויקט) הגדרות הפרויקט בצד ימין.
  3. בקטע 'פרויקט Google Cloud Platform (GCP)', לוחצים על שינוי פרויקט.
  4. מזינים את מספר הפרויקט ב-GCP ולוחצים על הגדרת פרויקט.
  5. לוחצים על Deploy (פריסה) >בדיקת פריסות.
  6. צריך לוודא שסוג הפריסה הוא תוסף Google Workspace. אם צריך, בחלק העליון של תיבת הדו-שיח, לוחצים על 'הפעלת סוגי פריסה' הפעלת סוגי פריסה ובוחרים באפשרות תוסף Google Workspace בתור סוג הפריסה.
  7. לצד אפליקציות: Gmail, לוחצים על התקנה.
  8. לוחצים על סיום.

עכשיו אפשר לראות את התוסף בתיבת הדואר הנכנס של Gmail.

  1. פותחים את Gmail במחשב.
  2. בחלונית השמאלית, לוחצים על Expense It! התוסף להשקיע אותו! סמל של קבלה מופיע. יכול להיות שתצטרכו ללחוץ על 'עוד תוספים' עוד תוספים כדי למצוא אותו.
  3. פותחים אימייל, עדיף לקבל קבלה עם הוצאות.
  4. כדי לפתוח את התוסף, לוחצים על Expense It! בחלונית שמשמאל. להשקיע אותו! סמל של קבלה.
  5. משקיעים כסף! גישה לחשבון Google שלכם על ידי לחיצה על אישור גישה ופועלים לפי ההנחיות.

בתוסף מוצג טופס פשוט לצד הודעה פתוחה ב-Gmail. הוא עדיין לא מבצע שום פעולה אחרת, אבל בקטע הבא נרחיב את הפונקציונליות שלו.

כדי לראות עדכונים לתוסף במהלך שיעור ה-Lab הזה, צריך רק לשמור את הקוד ולרענן את Gmail. אין צורך בפריסות נוספות.

4. גישה להודעות אימייל

הוסיפו קוד שמאחזר תוכן אימייל ומשנים את הקוד כדי שיהיה יותר ארגון.

לצד 'קבצים', לוחצים על סמל ההוספה הוסף קובץ > הסקריפט ויצירת קובץ בשם Cards. יוצרים קובץ סקריפט שני בשם Helpers. מערכת Cards.gs יוצרת את הכרטיס ומשתמשת בפונקציות מ-Helpers.gs כדי לאכלס שדות בטופס על סמך התוכן של האימייל.

מחליפים את קוד ברירת המחדל ב-Cards.gs בקוד הבא:

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;
}

כדי למלא מראש את הטופס כארגומנט אופציונלי, הפונקציה createExpensesCard מקבלת מערך של ערכים. הפונקציה יכולה להציג הודעת סטטוס אופציונלית, בצבע אדום אם הסטטוס מתחיל ב"שגיאה:", ובמקרים אחרים הוא ירוק. במקום להוסיף כל שדה לטופס באופן ידני, פונקציה מסייעת שנקראת createFormSection מבצעת בלולאה את תהליך היצירה של ווידג'טים של קלט טקסט, מגדירה כל ערך ברירת מחדל עם setValue, ואז מוסיפה את הווידג'טים לקטעים המתאימים בכרטיס.

עכשיו צריך להחליף את קוד ברירת המחדל ב-Helpers.gs בקוד הבא:

/**
 * 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';
}

לפונקציות ב-Helpers.gs נשלחת קריאה עד getContextualAddon כדי לקבוע את הערכים שמולאו מראש בטופס. בשלב הזה, הפונקציות האלה יחזירו רק את המחרוזת "TODO" כי תטמיעו את הלוגיקה של המילוי מראש בשלב מאוחר יותר.

בשלב הבא, מעדכנים את הקוד ב-GetContextualAddon.gs כך שהוא ישתמש בקוד ב-Cards.gs וב-Helpers.gs. מחליפים את הקוד שב-GetContextualAddon.gs בקוד הבא:

/**
 * 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);
}

שימו לב לפונקציה החדשה getCurrentMessage, שמשתמשת באירוע שסופק על ידי Gmail כדי לקרוא את ההודעה הפתוחה כרגע של המשתמש. כדי שהפונקציה הזו תפעל, צריך להוסיף עוד היקף למניפסט של הסקריפט, שמאפשר גישה לקריאה בלבד להודעות ב-Gmail.

ב-appscript.json, מעדכנים את ה-oauthScopes כך שיבקש גם את ההיקף של 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"
],

ב-Gmail, מפעילים את התוסף, ומאשרים גישה לאפשרות Expense It! כדי להציג הודעות אימייל. שדות הטופס ימולאו עכשיו מראש באפשרות 'TODO'.

5. אינטראקציה עם Google Sheets

The Expense It! לתוסף יש טופס שבאמצעותו המשתמש יכול להזין פרטים על הוצאה, אבל אין מקום לפרטים האלה. בואו נוסיף לחצן ששולח את נתוני הטופס לגיליון אלקטרוני ב-Google Sheets.

כדי להוסיף לחצן, נשתמש במחלקה ButtonSet. כדי להתממשק עם Google Sheets, נשתמש בשירות Google Sheets.

שינוי של createFormSection כדי שיוחזר לחצן עם התווית 'שליחה' כחלק מקטע הטופס של הכרטיס. זה מה שצריך לעשות:

  1. יצירת לחצן טקסט באמצעות CardService.newTextButton(), עם התווית 'שליחה' באמצעות CardService.TextButton.setText().
  2. מעצבים את הלחצן כך שכאשר לוחצים עליו, הפעולה הבאה של submitForm תופעל דרך CardService.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];
  });
}
  1. אפשר ליצור ווידג'ט למערך לחצנים באמצעות CardService.newButtonSet() ולהוסיף את לחצן הטקסט לרכיב המוגדר ב-CardService.ButtonSet.addButton().
  2. צריך להוסיף את הווידג'ט של קבוצת הלחצנים לקטע הטופס של הכרטיס באמצעות CardService.CardSection.addWidget().

באמצעות כמה שורות קוד בלבד, אנחנו יכולים לפתוח גיליון אלקטרוני לפי כתובת ה-URL שלו ולהוסיף שורת נתונים לאותו הגיליון. חשוב לשים לב שהקלט בטופס מועבר לפונקציה כחלק מהאירוע e, ואנחנו בודקים שהמשתמש סיפק את כל השדות. בהנחה שלא מתרחשות שגיאות, אנחנו יוצרים כרטיס הוצאות ריק עם סטטוס חיובי. אם נזהה שגיאה, נחזיר את הכרטיס המקורי שמולא יחד עם הודעת השגיאה. בעזרת פונקציית העזרה objToArray, קל יותר להמיר את התשובות לטופס למערך, ואז ניתן לצרף אותו לגיליון האלקטרוני.

לסיום, צריך לעדכן את הקטע oauthScopes בappsscript.json ולבקש שוב את ההיקף https://www.googleapis.com/auth/spreadsheets. בהענקת הרשאה להיקף הזה, התוסף יכול לקרוא ולשנות קובצי Google Sheets של המשתמש.

"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"
],

אם עדיין לא יצרת גיליון אלקטרוני חדש, עליך ליצור אותו בכתובת https://docs.google.com/spreadsheets/.

עכשיו צריך להפעיל מחדש את התוסף ולנסות לשלוח את הטופס. הקפידו להזין את כתובת ה-URL המלאה של כתובת היעד בשדה כתובת ה-URL של הגיליון האלקטרוני.

6. אחסון ערכים באמצעות השירות 'מאפיינים'

פעמים רבות, משתמשים מתעדים הוצאות רבות באותו גיליון אלקטרוני, כך שעדיף להציע את כתובת ה-URL העדכנית ביותר של הגיליון האלקטרוני כערך ברירת מחדל בכרטיס. כדי לדעת מהי כתובת ה-URL העדכנית ביותר של הגיליון האלקטרוני, צריך לשמור את המידע הזה בכל פעם שנעשה שימוש בתוסף.

שירות הנכסים מאפשר לנו לשמור צמדי מפתח/ערך. במקרה שלנו, מפתח סביר הוא "SPREAD המשתמש_URL" והערך יהיה כתובת ה-URL עצמה. כדי לאחסן ערך כזה, צריך לשנות את submitForm ב-Cards.gs כך שכתובת ה-URL של הגיליון האלקטרוני תאוחסן כנכס כשתוסיפו שורה חדשה לגיליון.

הערה: לנכסים יכול להיות אחת משלוש היקפים: סקריפט, משתמש או מסמך. היקף ההרשאות של המסמך לא רלוונטי לתוספים ל-Gmail, אבל הוא רלוונטי לסוג נפרד של תוסף כשמאחסנים מידע ספציפי במסמך מסוים ב-Google Docs או בגיליון ב-Sheets. עבור התוסף שלנו, ההתנהגות הרצויה היא לאפשר למשתמש לראות את הגיליון האלקטרוני העדכני שלו (בניגוד לגיליון האלקטרוני של מישהו אחר) כאפשרות ברירת המחדל בטופס. כתוצאה מכך, אנחנו בוחרים את ההיקף ברמת משתמש ולא את ההיקף script.

יש להשתמש ב-PropertiesService.getUserProperties().setProperty() כדי לשמור את כתובת ה-URL של הגיליון האלקטרוני. צריך להוסיף את הפריטים הבאים אל submitForm ב-Cards.gs:

PropertiesService.getUserProperties().setProperty('SPREADSHEET_URL', 
    res['Spreadsheet URL']);

לאחר מכן צריך לשנות את הפונקציה getSheetUrl ב-Helpers.gs כדי להחזיר את הנכס המאוחסן, כך שהמשתמשים יראו את כתובת ה-URL העדכנית ביותר בכל פעם שהם ישתמשו בתוסף. צריך להשתמש ב-PropertiesService.getUserProperties().getProperty() כדי לקבל את ערך הנכס.

/**
 * Determines most recent spreadsheet URL.
 * Returns null if no URL was previously submitted.
 *
 * @returns {String}
 */
function getSheetUrl() {
  return PropertiesService.getUserProperties().getProperty('SPREADSHEET_URL');
}

לסיום, כדי לגשת לשירות הנכס, גם הסקריפט יצטרך לקבל הרשאה. מוסיפים את ההיקף https://www.googleapis.com/auth/script.storage למניפסט כמו קודם כדי לאפשר לתוסף לקרוא ולכתוב פרטי נכס.

7. ניתוח ההודעה ב-Gmail

כדי להציל באמת נמלא מראש את הטופס במידע רלוונטי לגבי ההוצאה מהאימייל. כבר יצרנו פונקציות ב-Helpers.gs שממלאות את התפקיד הזה, אבל בינתיים החזרנו רק "TODO" עבור התאריך, הסכום ותיאור ההוצאה.

לדוגמה, אנחנו יכולים לקבל את התאריך שבו התקבל האימייל ולהשתמש בו כערך ברירת המחדל של תאריך ההוצאה.

/**
 * Determines date the email was received.
 *
 * @param {Message} message - The message currently open.
 * @returns {String}
 */
function getReceivedDate(message) {
  return message.getDate().toLocaleDateString();
}

מטמיעים את שתי הפונקציות הנותרות:

  1. getExpenseDescription עשוי לכלול הצטרפות גם לשם השולח וגם לנושא ההודעה, למרות שיש דרכים מתוחכמות יותר לנתח את גוף ההודעה ולספק תיאור מדויק עוד יותר.
  2. בשביל getLargestAmount, כדאי לחפש סמלים ספציפיים שקשורים לכסף. בקבלות בדרך כלל מוצגים כמה ערכים, למשל מיסים ועמלות אחרות. חישבו איך לזהות את הסכום הנכון. אפשר להשתמש גם בביטויים רגולריים.

אם אתם צריכים עוד קצת השראה, תוכלו לעיין במאמרי העזרה של GmailMessage או לבדוק את קוד הפתרון שהורדתם בתחילת ה-Codelab. אחרי פיתוח הטמעות משלכם לכל הפונקציות ב-Helpers.gs, צאו לדרך עם התוסף! אפשר לפתוח קבלות ולהתחיל לרשום אותן בגיליון אלקטרוני.

8. ניקוי הטופס עם פעולות בכרטיס

מה קורה אם מוציאים את הסכום? מזהה בטעות הוצאה באימייל פתוח וממלא מראש את הטופס במידע שגוי? המשתמש מנקה את הטופס. המחלקה CardAction מאפשרת לציין פונקציה שמופעלת כשמשתמש לוחץ על הפעולה. נשתמש בו כדי לאפשר למשתמש לנקות את הטופס במהירות.

צריך לשנות את createExpensesCard כך שהכרטיס שמחזיר יכלול פעולה בכרטיס עם התווית 'ניקוי טופס'. וכשלוחצים על הפונקציה clearForm הבאה, אפשר להדביק אותה ב-Cards.gs. יהיה עליך להעביר את הפונקציה opt_status כפרמטר בשם "Status" לפעולה כדי לוודא שאחרי שהטופס נמחק, הודעת הסטטוס תישאר. חשוב לזכור שפרמטרים אופציונליים של פעולות צריכים להיות מסוג Object.<string, string>, ולכן אם הערך opt_status לא זמין, עליכם להעביר את הערך {'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. יצירת גיליון אלקטרוני

מעבר לשימוש ב-Google Apps Script כדי לערוך גיליון אלקטרוני קיים, אפשר ליצור גיליון אלקטרוני חדש לגמרי באופן פרוגרמטי. עבור התוסף שלנו, נאפשר למשתמש ליצור גיליון אלקטרוני לגבי הוצאות. כדי להתחיל, צריך להוסיף את קטע הכרטיסים הבא לכרטיס שמחזיר 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);

עכשיו, כשהמשתמש ילחץ על הגיליון החדש לחצן התוסף יוצר גיליון אלקטרוני חדש בפורמט של שורת כותרת שהוקפאה כך שהוא תמיד יהיה גלוי. המשתמש מציין כותרת לגיליון האלקטרוני החדש בטופס, אבל מומלץ להוסיף ערך ברירת מחדל במקרה שהטופס ריק. בהטמעה של createExpensesSheet, מחזירים כרטיס כמעט זהה לכרטיס הקיים עם הוספה של הודעת סטטוס מתאימה ומילוי מראש של שדה כתובת ה-URL בכתובת ה-URL של הגיליון האלקטרוני החדש.

10. מעולה!

עיצבתם והטמעתם בהצלחה תוסף ל-Gmail שמוצא הוצאות באימייל ועוזר למשתמשים לרשום את ההוצאות בגיליון אלקטרוני תוך שניות ספורות. השתמשת ב-Google Apps Script כדי להתממשק עם מספר ממשקי API של Google ועם נתונים קבועים בין מספר הפעלות של התוסף.

שיפורים אפשריים

תנו לדמיון לכוון את הדרך כשאתם משפרים את Expense It!, אבל הנה כמה רעיונות ליצירת מוצר שימושי עוד יותר:

  • קישור לגיליון האלקטרוני לאחר שהמשתמש תועד הוצאה
  • הוספה של היכולת לערוך או לבטל רישום ביומן של הוצאות
  • כדאי לשלב ממשקי API חיצוניים כדי לאפשר למשתמשים לבצע תשלומים ולבקש כסף

מידע נוסף