1. ภาพรวม
ในโค้ดแล็บนี้ คุณจะได้ใช้ Google Apps Script เพื่อเขียนส่วนเสริม Google Workspace สำหรับ Gmail ที่ช่วยให้ผู้ใช้เพิ่มข้อมูลใบเสร็จจากอีเมลไปยังสเปรดชีตได้โดยตรงภายใน Gmail เมื่อผู้ใช้ได้รับใบเสร็จทางอีเมล ผู้ใช้จะเปิดส่วนเสริมซึ่งจะดึงข้อมูลค่าใช้จ่ายที่เกี่ยวข้องจากอีเมลโดยอัตโนมัติ ผู้ใช้สามารถแก้ไขข้อมูลค่าใช้จ่าย แล้วส่งเพื่อบันทึกค่าใช้จ่ายลงในสเปรดชีต Google ชีต
สิ่งที่คุณจะได้เรียนรู้
- สร้างส่วนเสริม Google Workspace สำหรับ Gmail โดยใช้ Google Apps Script
- แยกวิเคราะห์อีเมลด้วย Google Apps Script
- โต้ตอบกับ Google ชีตผ่าน 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 ใหม่และเปิดไฟล์ Manifest
- ไปที่ script.google.com จากที่นี่ คุณจะสร้าง จัดการ และตรวจสอบโปรเจ็กต์ Apps Script ได้
- หากต้องการสร้างโปรเจ็กต์ใหม่ ให้คลิกโปรเจ็กต์ใหม่ที่ด้านซ้ายบน โปรเจ็กต์ใหม่จะเปิดขึ้นพร้อมไฟล์เริ่มต้นชื่อ
Code.gsปล่อยให้Code.gsอยู่เฉยๆ ก่อน แล้วค่อยจัดการในภายหลัง - คลิกโปรเจ็กต์ที่ไม่มีชื่อ ตั้งชื่อโปรเจ็กต์เป็น Expense It! แล้วคลิกเปลี่ยนชื่อ
- คลิกการตั้งค่าโปรเจ็กต์
ทางด้านซ้าย - เลือกช่องทำเครื่องหมายแสดงไฟล์ Manifest "appscript.json" ในเครื่องมือแก้ไข"
- คลิกตัดต่อวิดีโอ

- หากต้องการเปิดไฟล์ Manifest ให้คลิก
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"
}
}
โปรดให้ความสนใจเป็นพิเศษกับส่วนของไฟล์ Manifest ที่เรียกว่า contextualTriggers ส่วนนี้ของไฟล์ Manifest จะระบุฟังก์ชันที่ผู้ใช้กำหนดเพื่อเรียกใช้เมื่อเปิดใช้งานส่วนเสริมเป็นครั้งแรก ในกรณีนี้ ฟังก์ชันจะเรียกใช้ getContextualAddOn ซึ่งจะรับรายละเอียดเกี่ยวกับอีเมลที่เปิดอยู่และแสดงชุดการ์ดเพื่อแสดงต่อผู้ใช้
หากต้องการสร้างฟังก์ชัน getContextualAddOn ให้ทำตามขั้นตอนต่อไปนี้
- ทางด้านซ้าย ให้วางเมาส์เหนือ
Code.gsแล้วคลิกเมนู
> เปลี่ยนชื่อ - พิมพ์
GetContextualAddOnแล้วกดแป้นEnterApps Script จะต่อท้าย.gsในชื่อไฟล์โดยอัตโนมัติ คุณจึงไม่จำเป็นต้องพิมพ์นามสกุลไฟล์ หากคุณพิมพ์GetContextualAddOn.gsApps Script จะตั้งชื่อไฟล์เป็นGetContextualAddOn.gs.gs - ใน
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
หากต้องการติดตั้งใช้งานและเรียกใช้ส่วนเสริม ให้ทำตามขั้นตอนต่อไปนี้
- เปิดโปรเจ็กต์ GCP แล้วคัดลอกหมายเลขโปรเจ็กต์
- จากโปรเจ็กต์ Apps Script ให้คลิกการตั้งค่าโปรเจ็กต์
ทางด้านซ้าย - ในส่วน "โปรเจ็กต์ Google Cloud Platform (GCP)" ให้คลิกเปลี่ยนโปรเจ็กต์
- ป้อนหมายเลขโปรเจ็กต์ของโปรเจ็กต์ GCP แล้วคลิกตั้งค่าโปรเจ็กต์
- คลิกทำให้ใช้งานได้> การทดสอบการติดตั้งใช้งาน
- ตรวจสอบว่าประเภทการทำให้ใช้งานได้คือส่วนเสริมของ Google Workspace หากจำเป็น ให้คลิกเปิดใช้ประเภทการทำให้ใช้งานได้
ที่ด้านบนของกล่องโต้ตอบ แล้วเลือกส่วนเสริมของ Google Workspace เป็นประเภทการทำให้ใช้งานได้ - คลิกติดตั้งข้างแอปพลิเคชัน: Gmail
- คลิกเสร็จสิ้น
ตอนนี้คุณจะเห็นส่วนเสริมในกล่องจดหมาย Gmail แล้ว
- เปิด Gmail ในคอมพิวเตอร์
- ในแผงด้านขวา ให้คลิก Expense It! ส่วนเสริม
จะปรากฏขึ้น คุณอาจต้องคลิกส่วนเสริมเพิ่มเติม
เพื่อค้นหาส่วนเสริม - เปิดอีเมล โดยควรเป็นใบเสร็จที่มีค่าใช้จ่าย
- หากต้องการเปิดส่วนเสริม ให้คลิก Expense It! ในแผงด้านข้างทางขวา

- ให้สิทธิ์เข้าถึงบัญชี Google แก่ Expense It! โดยคลิกให้สิทธิ์เข้าถึง แล้วทำตามข้อความแจ้ง
ส่วนเสริมจะแสดงแบบฟอร์มง่ายๆ ข้างข้อความ Gmail ที่เปิดอยู่ ตอนนี้ยังไม่มีฟังก์ชันอื่น แต่คุณจะสร้างฟังก์ชันการทำงานของปุ่มนี้ในส่วนถัดไป
หากต้องการดูการอัปเดตส่วนเสริมขณะที่คุณทำแล็บนี้ต่อไป คุณเพียงแค่ต้องบันทึกโค้ดและรีเฟรช Gmail โดยไม่จำเป็นต้องติดตั้งใช้งานเพิ่มเติม
4. เข้าถึงข้อความอีเมล
เพิ่มโค้ดที่ดึงเนื้อหาอีเมลและแยกโค้ดออกเป็นโมดูลเพื่อให้จัดระเบียบได้ดียิ่งขึ้น
คลิกเพิ่ม
> สคริปต์ข้างไฟล์ แล้วสร้างไฟล์ชื่อ Cards สร้างไฟล์สคริปต์ที่ 2 ชื่อ 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 จัดหาให้เพื่ออ่านข้อความที่ผู้ใช้เปิดอยู่ หากต้องการให้ฟังก์ชันนี้ทำงานได้ ให้เพิ่มขอบเขตเพิ่มเติมลงในไฟล์ Manifest ของสคริปต์ที่อนุญาตให้เข้าถึงข้อความ 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 ชีต
ส่วนเสริม Expense It! มีแบบฟอร์มให้ผู้ใช้ป้อนรายละเอียดเกี่ยวกับค่าใช้จ่าย แต่ไม่มีที่เก็บรายละเอียดเหล่านั้น เรามาเพิ่มปุ่มที่จะส่งข้อมูลแบบฟอร์มไปยัง Google ชีตกัน
หากต้องการเพิ่มปุ่ม เราจะใช้คลาส ButtonSet หากต้องการเชื่อมต่อกับ Google ชีต เราจะใช้บริการ Google ชีต
แก้ไข createFormSection เพื่อแสดงปุ่มที่มีป้ายกำกับว่า "ส่ง" เป็นส่วนหนึ่งของส่วนแบบฟอร์มของการ์ด โปรดทำตามขั้นตอนต่อไปนี้
- สร้างปุ่มข้อความโดยใช้
CardService.newTextButton()ติดป้ายกำกับปุ่มว่า "ส่ง" โดยใช้CardService.TextButton.setText() - ออกแบบปุ่มเพื่อให้เมื่อคลิกแล้ว ระบบจะเรียกใช้
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];
});
}
- สร้างวิดเจ็ตชุดปุ่มโดยใช้
CardService.newButtonSet()แล้วเพิ่มปุ่มข้อความลงในชุดปุ่มด้วยCardService.ButtonSet.addButton() - เพิ่มวิดเจ็ตชุดปุ่มลงในส่วนแบบฟอร์มของบัตรโดยใช้
CardService.CardSection.addWidget()
เพียงใช้โค้ดไม่กี่บรรทัด เราก็สามารถเปิดสเปรดชีตด้วย URL แล้วต่อท้ายแถวของข้อมูลในชีตนั้นได้ โปรดทราบว่าระบบจะส่งอินพุตของแบบฟอร์มไปยังฟังก์ชันเป็นส่วนหนึ่งของเหตุการณ์ e และเราจะตรวจสอบว่าผู้ใช้ได้ระบุทุกช่องแล้ว หากไม่มีข้อผิดพลาด เราจะสร้างบัตรค่าใช้จ่ายที่ว่างเปล่าซึ่งมีสถานะเป็น "พร้อมใช้งาน" ในกรณีที่เราพบข้อผิดพลาด เราจะส่งคืนการ์ดที่กรอกข้อมูลเดิมพร้อมกับข้อความแสดงข้อผิดพลาด ฟังก์ชันตัวช่วย objToArray ช่วยให้แปลงคำตอบของแบบฟอร์มเป็นอาร์เรย์ได้ง่ายขึ้น ซึ่งจากนั้นจะนำไปต่อท้ายสเปรดชีตได้
สุดท้าย ให้อัปเดตส่วน oauthScopes ใน appsscript.json อีกครั้งเพื่อขอขอบเขต https://www.googleapis.com/auth/spreadsheets เมื่อได้รับอนุญาต ขอบเขตนี้จะช่วยให้ส่วนเสริมอ่านและแก้ไข Google ชีตของผู้ใช้ได้
"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 ปลายทางลงในช่องแบบฟอร์ม URL ของสเปรดชีต
6. จัดเก็บค่าด้วยบริการพร็อพเพอร์ตี้
บ่อยครั้งที่ผู้ใช้จะบันทึกค่าใช้จ่ายจำนวนมากลงในสเปรดชีตเดียวกัน ดังนั้นการเสนอ URL ของสเปรดชีตล่าสุดเป็นค่าเริ่มต้นในบัตรจึงสะดวก เราจะต้องจัดเก็บข้อมูลดังกล่าวทุกครั้งที่มีการใช้ส่วนเสริมเพื่อให้ทราบ URL ของสเปรดชีตล่าสุด
บริการพร็อพเพอร์ตี้ช่วยให้เราจัดเก็บคู่คีย์-ค่าได้ ในกรณีของเรา คีย์ที่เหมาะสมคือ "SPREADSHEET_URL" ส่วนค่าคือ URL เอง หากต้องการจัดเก็บค่าดังกล่าว คุณจะต้องแก้ไข submitForm ใน Cards.gs เพื่อให้ระบบจัดเก็บ URL ของสเปรดชีตเป็นพร็อพเพอร์ตี้เมื่อต่อท้ายแถวใหม่ในชีต
โปรดทราบว่าพร็อพเพอร์ตี้มีขอบเขต 3 อย่าง ได้แก่ สคริปต์ ผู้ใช้ หรือเอกสาร ขอบเขตเอกสารใช้ไม่ได้กับส่วนเสริม Gmail แม้ว่าจะเกี่ยวข้องกับส่วนเสริมอีกประเภทหนึ่งเมื่อจัดเก็บข้อมูลที่เฉพาะเจาะจงสำหรับ Google เอกสารหรือชีตใดชีตหนึ่ง สำหรับส่วนเสริมของเรา พฤติกรรมที่ต้องการคือให้แต่ละบุคคลเห็นสเปรดชีตล่าสุดของตนเอง (ไม่ใช่ของคนอื่น) เป็นตัวเลือกเริ่มต้นในแบบฟอร์ม ดังนั้นเราจึงเลือกขอบเขตผู้ใช้แทนขอบเขตสคริปต์
ใช้ 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 ลงในไฟล์ Manifest เหมือนเดิมเพื่อให้ส่วนเสริมอ่านและเขียนข้อมูลพร็อพเพอร์ตี้ได้
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();
}
ติดตั้งใช้งานฟังก์ชันที่เหลืออีก 2 ฟังก์ชัน
getExpenseDescriptionอาจต้องรวมทั้งชื่อผู้ส่งและหัวเรื่องของข้อความเข้าด้วยกัน แม้ว่าจะมีวิธีที่ซับซ้อนกว่าในการแยกวิเคราะห์เนื้อหาของข้อความและแสดงคำอธิบายที่แม่นยำยิ่งขึ้น- สำหรับ
getLargestAmountให้ลองมองหาสัญลักษณ์ที่เกี่ยวข้องกับเงินโดยเฉพาะ ใบเสร็จมักจะมีค่าหลายรายการ เช่น ภาษีและค่าธรรมเนียมอื่นๆ ลองคิดดูว่าคุณจะระบุจำนวนเงินที่ถูกต้องได้อย่างไร นิพจน์ทั่วไปอาจมีประโยชน์เช่นกัน
หากต้องการแรงบันดาลใจเพิ่มเติม โปรดดูเอกสารอ้างอิงสำหรับ GmailMessage หรือดูโค้ดโซลูชันที่คุณดาวน์โหลดไว้ตอนต้นของ Codelab เมื่อคิดการติดตั้งใช้งานฟังก์ชันทั้งหมดใน Helpers.gs ได้แล้ว ก็ลองใช้ส่วนเสริมของคุณได้เลย เปิดใบเสร็จและเริ่มบันทึกในสเปรดชีต
8. ล้างแบบฟอร์มด้วยการดำเนินการกับการ์ด
จะเกิดอะไรขึ้นหาก 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();
}
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 เพื่อเชื่อมต่อกับ Google API หลายรายการและจัดเก็บข้อมูลระหว่างการเรียกใช้ส่วนเสริมหลายครั้ง
การปรับปรุงที่เป็นไปได้
ปล่อยให้จินตนาการนำทางคุณขณะปรับปรุง Expense It! แต่เรามีไอเดียบางอย่างที่จะช่วยให้ผลิตภัณฑ์มีประโยชน์มากยิ่งขึ้น
- ลิงก์ไปยังสเปรดชีตเมื่อผู้ใช้บันทึกค่าใช้จ่ายแล้ว
- เพิ่มความสามารถในการแก้ไข/ยกเลิกการบันทึกค่าใช้จ่าย
- ผสานรวม API ภายนอกเพื่อให้ผู้ใช้ชำระเงินและขอรับเงินได้