با افزونه‌های Google Workspace، ایمیل را کاربردی‌تر کنید

۱. مرور کلی

در این آزمایشگاه کد، شما از اسکریپت Google Apps برای نوشتن یک افزونه Google Workspace برای Gmail استفاده خواهید کرد که به کاربران اجازه می‌دهد داده‌های رسید را از یک ایمیل به یک صفحه گسترده (spreadsheet) مستقیماً در Gmail اضافه کنند. وقتی کاربری رسیدی را از طریق ایمیل دریافت می‌کند، افزونه را باز می‌کند که به طور خودکار اطلاعات هزینه مربوطه را از ایمیل دریافت می‌کند. کاربر می‌تواند اطلاعات هزینه را ویرایش کرده و سپس آن را برای ثبت هزینه خود در یک صفحه گسترده Google Sheets ارسال کند.

آنچه یاد خواهید گرفت

  • با استفاده از اسکریپت برنامه‌های گوگل، یک افزونه‌ی Google Workspace برای جیمیل ایجاد کنید
  • تجزیه و تحلیل ایمیل با اسکریپت برنامه‌های گوگل
  • تعامل با گوگل شیت از طریق اسکریپت برنامه‌های گوگل
  • ذخیره مقادیر کاربر با استفاده از سرویس Properties اسکریپت برنامه‌های گوگل

آنچه نیاز دارید

  • دسترسی به اینترنت و مرورگر وب
  • یک حساب گوگل
  • برخی پیام‌ها، ترجیحاً رسیدهای ایمیل، در Gmail

۲. کد نمونه را دریافت کنید

هنگام کار با این آزمایشگاه کد، ممکن است ارجاع به یک نسخهٔ در حال کار از کدی که خواهید نوشت مفید باشد. مخزن گیت‌هاب شامل نمونه کدهایی است که می‌توانید به عنوان مرجع از آنها استفاده کنید.

برای دریافت کد نمونه، از خط فرمان، دستور زیر را اجرا کنید:

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

۳. یک افزونه‌ی پایه بسازید

با نوشتن کد برای یک نسخه ساده از افزونه که فرم هزینه را در کنار یک ایمیل نمایش می‌دهد، شروع کنید.

ابتدا، یک پروژه جدید Apps Script ایجاد کنید و فایل manifest آن را باز کنید.

  1. به script.google.com بروید. از اینجا می‌توانید پروژه‌های اسکریپت برنامه‌ها (Apps Script) خود را ایجاد، مدیریت و نظارت کنید.
  2. برای ایجاد یک پروژه جدید، در بالا سمت چپ، روی «پروژه جدید» کلیک کنید. پروژه جدید با یک فایل پیش‌فرض به نام Code.gs باز می‌شود. فعلاً Code.gs به حال خود رها کنید، بعداً با آن کار خواهید کرد.
  3. روی پروژه بدون عنوان کلیک کنید، نام پروژه خود را Expense It! بگذارید و روی تغییر نام کلیک کنید.
  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!، به یک پروژه‌ی پلتفرم ابری گوگل (GCP) نیاز دارید که پروژه‌های Apps Script از آن برای مدیریت مجوزها، سرویس‌های پیشرفته و سایر جزئیات استفاده می‌کنند. برای کسب اطلاعات بیشتر، به پروژه‌های پلتفرم ابری گوگل مراجعه کنید.

برای نصب و اجرای افزونه، مراحل زیر را دنبال کنید:

  1. پروژه GCP خود را باز کنید و شماره پروژه آن را کپی کنید .
  2. از پروژه Apps Script خود، در سمت چپ، روی تنظیمات پروژه کلیک کنید تنظیمات پروژه .
  3. در بخش «پروژه پلتفرم ابری گوگل (GCP)، روی تغییر پروژه کلیک کنید.
  4. شماره پروژه GCP خود را وارد کنید، سپس روی تنظیم پروژه کلیک کنید.
  5. روی استقرار > آزمایش استقرارها کلیک کنید.
  6. مطمئن شوید که نوع استقرار ، افزونه‌ی Google Workspace باشد. در صورت لزوم، در بالای پنجره‌ی محاوره‌ای، روی «فعال کردن انواع استقرار» کلیک کنید. فعال کردن انواع استقرار و افزونه‌ی Google Workspace را به عنوان نوع استقرار انتخاب کنید.
  7. در کنار «برنامه(ها): Gmail» ، روی «نصب» کلیک کنید.
  8. روی انجام شد کلیک کنید.

حالا می‌توانید افزونه را در صندوق ورودی جیمیل خود مشاهده کنید.

  1. در رایانه‌تان، Gmail را باز کنید.
  2. در پنل سمت راست، گزینه‌ی «هزینه‌اش را پرداخت کن!» آیکون رسید «خرجش کن!» افزونه ظاهر می‌شود. شاید لازم باشد روی افزونه‌های بیشتر کلیک کنید. افزونه‌های بیشتر تا آن را پیدا کنم.
  3. یک ایمیل، ترجیحاً رسید حاوی هزینه‌ها، را باز کنید.
  4. برای باز کردن افزونه، در پنل سمت راست، روی Expense It! کلیک کنید. آیکون رسید «خرجش کن!» .
  5. با کلیک روی «مجاز کردن دسترسی» و دنبال کردن دستورالعمل‌ها، به برنامه‌ی «Expense It!» اجازه دسترسی به حساب گوگل خود را بدهید.

این افزونه یک فرم ساده را در کنار یک پیام باز Gmail نشان می‌دهد. هنوز کار دیگری انجام نمی‌دهد، اما در بخش بعدی عملکرد آن را توسعه خواهید داد.

برای مشاهده به‌روزرسانی‌های افزونه خود در ادامه این آزمایش، فقط باید کد خود را ذخیره کرده و Gmail را به‌روزرسانی کنید. هیچ پیاده‌سازی اضافی لازم نیست.

۴. دسترسی به پیام‌های ایمیل

کدی اضافه کنید که محتوای ایمیل را دریافت کند و برای سازماندهی بیشتر، کد را ماژولار کنید.

در کنار فایل‌ها، روی افزودن کلیک کنید اضافه کردن فایل اسکریپت را اجرا کنید و فایلی به نام 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 آرایه‌ای از مقادیر را برای پر کردن اولیه فرم به عنوان یک آرگومان اختیاری دریافت می‌کند. این تابع می‌تواند یک پیام وضعیت اختیاری نمایش دهد که اگر وضعیت با "Error:" شروع شود، قرمز و در غیر این صورت سبز است. به جای اضافه کردن دستی هر فیلد به فرم، یک تابع کمکی به نام 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"
],

در جیمیل، افزونه خود را اجرا کنید و به Expense It! اجازه دسترسی برای مشاهده پیام‌های ایمیل را بدهید. فیلدهای فرم اکنون با «TODO» از قبل پر شده‌اند.

۵. تعامل با گوگل شیت

افزونه‌ی Expense It! فرمی دارد که کاربر می‌تواند جزئیات مربوط به یک هزینه را در آن وارد کند، اما این جزئیات جایی برای نمایش ندارند. بیایید دکمه‌ای اضافه کنیم که داده‌های فرم را به یک Google Sheet ارسال کند.

برای اضافه کردن یک دکمه، از کلاس 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 را درخواست کنید. وقتی این دامنه مجاز شد، افزونه به آن اجازه می‌دهد تا صفحات گوگل کاربر را بخواند و تغییر دهد.

"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 مقصد خود را در فیلد فرم Spreadsheet URL وارد می‌کنید.

۶. ذخیره مقادیر با سرویس Properties

اغلب اوقات، کاربران هزینه‌های زیادی را در یک صفحه گسترده ثبت می‌کنند، بنابراین ارائه جدیدترین آدرس اینترنتی صفحه گسترده به عنوان مقدار پیش‌فرض در کارت، مناسب خواهد بود. برای اینکه جدیدترین آدرس اینترنتی صفحه گسترده را بدانیم، باید هر بار که از افزونه استفاده می‌شود، آن اطلاعات را ذخیره کنیم.

سرویس Properties به ما امکان ذخیره جفت‌های کلید-مقدار را می‌دهد. در مورد ما، یک کلید معقول "SPREADSHEET_URL" خواهد بود در حالی که مقدار، خود URL خواهد بود. برای ذخیره چنین مقداری، باید submitForm در Cards.gs تغییر دهید تا URL صفحه گسترده هنگام افزودن یک ردیف جدید به برگه، به عنوان یک ویژگی ذخیره شود.

توجه داشته باشید که ویژگی‌ها می‌توانند یکی از سه حوزه را داشته باشند: اسکریپت، کاربر یا سند . حوزه سند برای افزونه‌های جیمیل اعمال نمی‌شود، اگرچه هنگام ذخیره اطلاعات خاص برای یک سند یا برگه گوگل خاص، به نوع جداگانه‌ای از افزونه مربوط می‌شود. برای افزونه ما، رفتار مطلوب این است که یک فرد آخرین صفحه گسترده خود (برخلاف شخص دیگری) را به عنوان گزینه پیش‌فرض در فرم ببیند. در نتیجه، ما حوزه کاربر را به جای حوزه اسکریپت انتخاب می‌کنیم.

برای ذخیره آدرس صفحه گسترده از PropertiesService.getUserProperties().setProperty() استفاده کنید. کد زیر را به 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');
}

در نهایت، برای دسترسی به سرویس Property، اسکریپت نیز باید مجاز شود. مانند قبل، دامنه https://www.googleapis.com/auth/script.storage را به مانیفست اضافه کنید تا افزونه شما بتواند اطلاعات Property را بخواند و بنویسد.

۷. تجزیه و تحلیل پیام جیمیل

برای صرفه‌جویی واقعی در وقت کاربران، بیایید فرم را از قبل با اطلاعات مرتبط با هزینه از طریق ایمیل پر کنیم. ما قبلاً توابعی را در 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 را بررسی کنید یا کد راه‌حلی را که در ابتدای آزمایشگاه کد دانلود کرده‌اید، بررسی کنید. وقتی پیاده‌سازی‌های خودتان را برای همه توابع Helpers.gs ابداع کردید، افزونه خود را امتحان کنید! رسیدها را باز کنید و شروع به ثبت آنها در یک صفحه گسترده کنید!

۸. فرم را با اقدامات کارت پاک کنید

چه اتفاقی می‌افتد اگر Expense It! هزینه‌ای را در یک ایمیل باز شده اشتباه شناسایی کند و فرم را با اطلاعات نادرست از قبل پر کند؟ کاربر فرم را پاک می‌کند. کلاس CardAction به ما امکان می‌دهد تابعی را مشخص کنیم که هنگام کلیک روی عمل فراخوانی می‌شود. بیایید از آن برای ارائه راهی سریع به کاربر برای پاک کردن فرم استفاده کنیم.

createExpensesCard طوری تغییر دهید که کارتی که برمی‌گرداند، یک اکشن کارت با برچسب "پاک کردن فرم" داشته باشد و وقتی روی آن کلیک می‌شود، تابع clearForm زیر را فراخوانی کند که می‌توانید آن را در Cards.gs پیست کنید. برای اطمینان از اینکه وقتی فرم پاک می‌شود، پیام وضعیت باقی می‌ماند، باید opt_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();
}

۹. یک صفحه گسترده ایجاد کنید

فراتر از استفاده از اسکریپت Google Apps برای ویرایش یک صفحه گسترده موجود، می‌توانید یک صفحه گسترده کاملاً جدید را به صورت برنامه‌نویسی ایجاد کنید. برای افزونه ما، بیایید به کاربر اجازه دهیم یک صفحه گسترده برای هزینه‌ها ایجاد کند. برای شروع، بخش کارت زیر را به کارتی که 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 صفحه‌گسترده‌ی جدید از قبل.

۱۰. تبریک می‌گویم!

شما با موفقیت یک افزونه جیمیل طراحی و پیاده‌سازی کرده‌اید که هزینه‌ای را در یک ایمیل پیدا می‌کند و به کاربران کمک می‌کند تا آن هزینه را تنها در عرض چند ثانیه در یک صفحه گسترده ثبت کنند. شما از اسکریپت Google Apps برای ارتباط با چندین API گوگل استفاده کرده‌اید و داده‌ها را بین چندین اجرای افزونه ذخیره کرده‌اید.

بهبودهای احتمالی

بگذارید تخیلتان شما را در بهبود «هزینه‌اش کن!» راهنمایی کند، اما در اینجا چند ایده برای ساختن محصولی حتی مفیدتر ارائه شده است:

  • پس از ثبت هزینه توسط کاربر، به صفحه گسترده لینک دهید
  • اضافه کردن قابلیت ویرایش/لغو ثبت هزینه‌ها
  • ادغام API های خارجی برای امکان پرداخت و درخواست وجه توسط کاربران

اطلاعات بیشتر