1. ภาพรวม
ใน Codelab นี้ คุณจะใช้ 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! แล้วคลิกเปลี่ยนชื่อ
- คลิกการตั้งค่าโปรเจ็กต์ ทางด้านซ้าย
- เลือกช่องทำเครื่องหมาย Show "appscript.json" "ไฟล์ Manifest ในตัวแก้ไข"
- คลิกตัดต่อวิดีโอ
- หากต้องการเปิดไฟล์ 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
และกดแป้นEnter
Apps Script จะเพิ่ม.gs
ต่อท้ายชื่อไฟล์โดยอัตโนมัติ คุณจึงไม่ต้องพิมพ์นามสกุลไฟล์ หากคุณพิมพ์GetContextualAddOn.gs
แล้ว Apps 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 ประกอบด้วยการ์ดที่แบ่งออกเป็น 1 ส่วนขึ้นไป โดยแต่ละส่วนจะมีวิดเจ็ตที่แสดงและรับข้อมูลจากผู้ใช้ได้ ฟังก์ชัน getContextualAddOn
จะสร้างการ์ดใบเดียวที่มีรายละเอียดเกี่ยวกับค่าใช้จ่ายที่พบในอีเมล การ์ดมี 1 ส่วนที่มีช่องป้อนข้อความสำหรับข้อมูลที่เกี่ยวข้อง ฟังก์ชันจะแสดงผลอาร์เรย์ของการ์ดของส่วนเสริม ในกรณีนี้ อาร์เรย์ที่แสดงผลจะมีการ์ดเพียง 1 รายการ
ก่อนใช้งาน 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 ในคอมพิวเตอร์
- ในแผงด้านขวา ให้เลือก "ค่าใช้จ่าย!" ส่วนเสริม จะปรากฏขึ้น คุณอาจต้องคลิกส่วนเสริมเพิ่มเติม เพื่อค้นหา
- เปิดอีเมล (ควรเป็นใบเสร็จที่ระบุค่าใช้จ่าย)
- หากต้องการเปิดส่วนเสริม ให้คลิกค่าใช้จ่าย!
- ให้ค่าใช้จ่าย ให้เข้าถึงบัญชี Google ของคุณโดยคลิกให้สิทธิ์เข้าถึงและทำตามข้อความแจ้ง
ส่วนเสริมจะแสดงแบบฟอร์มง่ายๆ ควบคู่ไปกับข้อความ Gmail ที่เปิดอยู่ ยังไม่ได้ทำอะไรเลย แต่คุณจะสร้างฟังก์ชันการทำงานในส่วนถัดไป
หากต้องการดูการอัปเดตส่วนเสริมขณะดำเนินการในห้องทดลองนี้ คุณเพียงแค่บันทึกรหัสและรีเฟรช Gmail โดยไม่จำเป็นต้องติดตั้งใช้งานเพิ่มเติม
4. เข้าถึงข้อความอีเมล
เพิ่มโค้ดที่ดึงเนื้อหาอีเมลและปรับโค้ดเป็นโมดูลเพื่อให้เป็นระเบียบมากขึ้น
คลิกเพิ่ม ข้าง Files > เขียนสคริปต์และสร้างไฟล์ชื่อ 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';
}
getContextualAddon
จะเรียกฟังก์ชันใน Helpers.gs
เพื่อระบุค่าที่กรอกไว้ล่วงหน้าในแบบฟอร์ม ในตอนนี้ ฟังก์ชันเหล่านี้จะแสดงผลสตริง "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 ชีต
ค่าใช้จ่ายก็คุ้มค่า ส่วนเสริมมีแบบฟอร์มให้ผู้ใช้ป้อนรายละเอียดเกี่ยวกับค่าใช้จ่าย แต่รายละเอียดเหล่านั้นไม่จำเป็นต้องอยู่ที่นั่น มาเพิ่มปุ่มสำหรับส่งข้อมูลแบบฟอร์มไปยัง 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 ของสเปรดชีตเป็นพร็อพเพอร์ตี้เมื่อนำแถวใหม่มาต่อท้ายชีต
โปรดทราบว่าพร็อพเพอร์ตี้อาจมีขอบเขต 1 จาก 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. ล้างแบบฟอร์มด้วยการทำงานของการ์ด
จะเกิดอะไรขึ้นหากรายจ่าย หากระบุค่าใช้จ่ายในอีเมลที่เปิดอยู่ผิด แล้วระบบกรอกข้อมูลที่ไม่ถูกต้องในแบบฟอร์ม ผู้ใช้ล้างแบบฟอร์ม คลาส CardAction ช่วยให้เราระบุฟังก์ชันที่จะเรียกใช้เมื่อมีการคลิกการดำเนินการ มาลองใช้ฟีเจอร์นี้เพื่อให้ผู้ใช้ล้างแบบฟอร์มได้อย่างรวดเร็วกัน
แก้ไข createExpensesCard
ให้การ์ดที่แสดงผลมีการทำงานของการ์ดที่มีป้ายกำกับ "ล้างแบบฟอร์ม" และเมื่อคลิกจะเรียกฟังก์ชัน clearForm
ต่อไปนี้ ซึ่งคุณสามารถวางลงใน Cards.gs
คุณจะต้องส่งใน opt_status
เป็นพารามิเตอร์ชื่อ "สถานะ" การดำเนินการเพื่อให้มั่นใจว่าเมื่อล้างฟอร์มแล้ว ข้อความสถานะจะยังอยู่ โปรดทราบว่าพารามิเตอร์ที่ไม่บังคับสำหรับการดำเนินการต้องเป็นประเภทออบเจ็กต์<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 ภายนอกเพื่อให้ผู้ใช้ชำระเงินและขอรับเงินได้