1. Ringkasan
Dalam codelab ini, Anda akan menggunakan Google Apps Script untuk menulis Add-on Google Workspace untuk Gmail yang memungkinkan pengguna menambahkan data tanda terima dari email ke spreadsheet langsung di Gmail. Saat pengguna menerima tanda terima melalui email, mereka akan membuka add-on yang secara otomatis mendapatkan informasi pengeluaran yang relevan dari email. Pengguna dapat mengedit informasi pengeluaran, lalu mengirimkannya untuk mencatat pengeluaran ke spreadsheet Google Spreadsheet.
Yang akan Anda pelajari
- Membuat Add-on Google Workspace untuk Gmail menggunakan Google Apps Script
- Mengurai email dengan Google Apps Script
- Berinteraksi dengan Google Spreadsheet melalui Google Apps Script
- Menyimpan nilai pengguna menggunakan layanan Properti Google Apps Script
Yang Anda butuhkan
- Akses ke internet dan browser web
- Akun Google
- Beberapa pesan, sebaiknya tanda terima email, di Gmail
2. Mendapatkan kode contoh
Saat Anda mempelajari codelab ini, mungkin akan berguna untuk merujuk pada versi kode yang berfungsi yang akan Anda tulis. Repositori GitHub berisi kode contoh yang dapat Anda gunakan sebagai referensi.
Untuk mendapatkan kode contoh, dari command line, jalankan:
git clone https://github.com/googleworkspace/gmail-add-on-codelab.git
3. Membuat add-on dasar
Mulai dengan menulis kode untuk versi sederhana add-on yang menampilkan formulir pengeluaran bersama email.
Pertama, buat project Apps Script baru dan buka file manifesnya.
- Buka script.google.com. Dari sini, Anda dapat membuat, mengelola, dan memantau project Apps Script.
- Untuk membuat project baru, di kiri atas, klik Project Baru. Project baru akan terbuka dengan file default bernama
Code.gs. BiarkanCode.gsseperti ini dulu, Anda akan menggunakannya nanti. - Klik Untitled project, beri nama project Anda Expense It!, lalu klik Rename.
- Di sebelah kiri, klik Setelan Project
. - Centang kotak Tampilkan file manifes "appscript.json" di editor.
- Klik Editor
. - Untuk membuka file manifes, di sebelah kiri, klik
appscript.json.
Di appscript.json, tentukan metadata yang terkait dengan add-on, seperti nama dan izin yang diperlukan. Ganti konten appsscript.json dengan setelan konfigurasi berikut:
{
"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"
}
}
Berikan perhatian khusus pada bagian manifes yang disebut contextualTriggers. Bagian manifes ini mengidentifikasi fungsi yang ditentukan pengguna untuk dipanggil saat add-on pertama kali diaktifkan. Dalam hal ini, aplikasi akan memanggil getContextualAddOn, yang mendapatkan detail tentang email yang terbuka dan menampilkan sekumpulan kartu kepada pengguna.
Untuk membuat fungsi getContextualAddOn, ikuti langkah-langkah berikut:
- Di sebelah kiri, arahkan kursor ke
Code.gs, lalu klik Menu
> Ganti nama. - Ketik
GetContextualAddOn, lalu tekan tombolEnter. Apps Script otomatis menambahkan.gske nama file Anda, jadi Anda tidak perlu mengetik ekstensi file. Jika Anda mengetikGetContextualAddOn.gs, Apps Script akan memberi nama file AndaGetContextualAddOn.gs.gs. - Di
GetContextualAddOn.gs, ganti kode default dengan fungsigetContextualAddOn:
/**
* 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()];
}
Antarmuka pengguna setiap Add-on Google Workspace terdiri dari kartu yang dibagi menjadi satu atau beberapa bagian, yang masing-masing berisi widget yang dapat menampilkan dan mendapatkan informasi dari pengguna. Fungsi getContextualAddOn membuat satu kartu yang mendapatkan detail tentang pengeluaran yang ditemukan dalam email. Kartu ini memiliki satu bagian yang berisi kolom input teks untuk data yang relevan. Fungsi ini menampilkan array kartu add-on. Dalam hal ini, array yang ditampilkan hanya menyertakan satu kartu.
Sebelum men-deploy add-on Expense It!, Anda memerlukan Project Google Cloud Platform (GCP), yang digunakan project Apps Script untuk mengelola otorisasi, layanan lanjutan, dan detail lainnya. Untuk mempelajari lebih lanjut, buka Project Google Cloud Platform.
Untuk men-deploy dan menjalankan add-on, ikuti langkah-langkah berikut:
- Buka project GCP Anda, lalu salin nomor project-nya.
- Dari project Apps Script Anda, di sebelah kiri, klik Project Settings
. - Di bagian "Project Google Cloud Platform (GCP)", klik Ubah project.
- Masukkan nomor project GCP Anda, lalu klik Set project.
- Klik Deploy > Test deployments.
- Pastikan jenis deployment adalah Add-on Google Workspace. Jika perlu, di bagian atas dialog, klik Aktifkan jenis deployment
, lalu pilih Add-on Google Workspace sebagai jenis deployment. - Di samping Aplikasi: Gmail, klik Instal.
- Klik Selesai.
Sekarang Anda dapat melihat add-on di kotak masuk Gmail Anda.
- Di komputer Anda, buka Gmail.
- Di panel samping kanan, Expense It! Add-on
akan muncul. Anda mungkin perlu mengklik Add-on Lainnya
untuk menemukannya. - Buka email, sebaiknya tanda terima dengan pengeluaran.
- Untuk membuka add-on, di panel samping kanan, klik Expense It!
. - Beri Expense It! akses ke Akun Google Anda dengan mengklik Authorize Access dan ikuti perintahnya.
Add-on menampilkan formulir sederhana di samping pesan Gmail yang terbuka. Fungsi ini belum melakukan apa pun, tetapi Anda akan membangun fungsinya di bagian berikutnya.
Untuk melihat update pada add-on saat Anda melanjutkan lab ini, Anda hanya perlu menyimpan kode dan memuat ulang Gmail. Tidak diperlukan deployment tambahan.
4. Mengakses pesan email
Tambahkan kode yang mengambil konten email dan modularisasi kode untuk mengatur kode dengan lebih baik.
Di samping File, klik Tambahkan
> Script, lalu buat file bernama Cards. Buat file skrip kedua bernama Helpers. Cards.gs membuat kartu dan menggunakan fungsi dari Helpers.gs untuk mengisi kolom dalam formulir berdasarkan konten email.
Ganti kode default di Cards.gs dengan kode ini:
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;
}
Fungsi createExpensesCard menggunakan array nilai untuk mengisi formulir secara otomatis sebagai argumen opsional. Fungsi ini dapat menampilkan pesan status opsional, yang berwarna merah jika status dimulai dengan "Error:", dan berwarna hijau jika tidak. Daripada menambahkan setiap kolom ke formulir secara manual, fungsi helper yang disebut createFormSection melakukan loop melalui proses pembuatan widget input teks, menetapkan setiap nilai default dengan setValue, lalu menambahkan widget ke bagian masing-masing di kartu.
Sekarang, ganti kode default di Helpers.gs dengan kode ini:
/**
* 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';
}
Fungsi di Helpers.gs dipanggil oleh getContextualAddon untuk menentukan nilai yang telah diisi otomatis pada formulir. Untuk saat ini, fungsi ini hanya akan menampilkan string "TODO" karena Anda akan menerapkan logika pengisian otomatis di langkah berikutnya.
Selanjutnya, perbarui kode di GetContextualAddon.gs sehingga memanfaatkan kode di Cards.gs dan Helpers.gs. Ganti kode di GetContextualAddon.gs dengan kode ini:
/**
* 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);
}
Perhatikan fungsi getCurrentMessage baru, yang menggunakan peristiwa yang disediakan oleh Gmail untuk membaca pesan yang saat ini dibuka pengguna. Agar fungsi ini berfungsi, tambahkan cakupan tambahan ke manifes skrip yang memungkinkan akses hanya baca ke pesan Gmail.
Di appscript.json, perbarui oauthScopes sehingga juga meminta cakupan 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"
],
Di Gmail, jalankan add-on Anda, dan beri otorisasi akses untuk Expense It! agar dapat melihat pesan email. Kolom formulir kini telah diisi otomatis dengan "TODO".
5. Berinteraksi dengan Google Spreadsheet
Add-on Expense It! memiliki formulir bagi pengguna untuk memasukkan detail tentang pengeluaran, tetapi detail tersebut tidak dapat dikirim ke mana pun. Mari tambahkan tombol yang mengirimkan data formulir ke Google Spreadsheet.
Untuk menambahkan tombol, kita akan menggunakan class ButtonSet. Untuk berinteraksi dengan Google Spreadsheet, kita akan menggunakan layanan Google Spreadsheet.
Ubah createFormSection untuk menampilkan tombol berlabel "Kirim" sebagai bagian dari bagian formulir kartu. Lakukan langkah-langkah berikut:
- Buat tombol teks menggunakan
CardService.newTextButton(), beri label tombol "Kirim" menggunakanCardService.TextButton.setText(). - Desain tombol sedemikian rupa sehingga saat diklik, tindakan
submitFormberikut dipanggil melaluiCardService.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];
});
}
- Buat widget set tombol menggunakan
CardService.newButtonSet()dan tambahkan tombol teks ke set tombol denganCardService.ButtonSet.addButton(). - Tambahkan widget set tombol ke bagian formulir kartu menggunakan
CardService.CardSection.addWidget().
Hanya dengan beberapa baris kode, kita dapat membuka spreadsheet berdasarkan URL-nya, lalu menambahkan baris data ke sheet tersebut. Perhatikan bahwa input formulir diteruskan ke fungsi sebagai bagian dari peristiwa e, dan kita memeriksa apakah pengguna telah mengisi semua kolom. Dengan asumsi tidak ada error, kita membuat kartu pengeluaran kosong dengan status yang menguntungkan. Jika kami menemukan error, kami akan menampilkan kartu yang diisi asli beserta pesan error. Fungsi bantuan objToArray memudahkan konversi respons formulir menjadi array, yang kemudian dapat ditambahkan ke spreadsheet.
Terakhir, perbarui bagian oauthScopes di appsscript.json lagi dan minta cakupan https://www.googleapis.com/auth/spreadsheets. Jika diizinkan, cakupan ini memungkinkan add-on membaca dan mengubah Spreadsheet Google pengguna.
"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"
],
Jika Anda belum membuat spreadsheet baru, buat di https://docs.google.com/spreadsheets/.
Sekarang jalankan kembali add-on dan coba kirimkan formulir. Pastikan Anda memasukkan URL lengkap URL tujuan ke dalam kolom formulir URL Spreadsheet.
6. Menyimpan nilai dengan layanan Properti
Sering kali, pengguna akan mencatat banyak pengeluaran ke spreadsheet yang sama, sehingga akan lebih mudah jika URL spreadsheet terbaru ditawarkan sebagai nilai default di kartu. Untuk mengetahui URL spreadsheet terbaru, kita perlu menyimpan informasi tersebut setiap kali add-on digunakan.
Layanan properti memungkinkan kita menyimpan key-value pair. Dalam kasus ini, kunci yang wajar adalah "SPREADSHEET_URL", sedangkan nilainya adalah URL itu sendiri. Untuk menyimpan nilai tersebut, Anda harus mengubah submitForm di Cards.gs sehingga URL spreadsheet disimpan sebagai properti saat menambahkan baris baru ke sheet.
Perhatikan bahwa properti dapat memiliki salah satu dari tiga cakupan: skrip, pengguna, atau dokumen. Cakupan dokumen tidak berlaku untuk add-on Gmail, meskipun relevan dengan jenis add-on terpisah saat menyimpan informasi khusus untuk Dokumen atau Spreadsheet Google tertentu. Untuk add-on kami, perilaku yang diinginkan adalah agar setiap individu dapat melihat spreadsheet terbarunya (bukan spreadsheet orang lain) sebagai opsi default di formulir. Oleh karena itu, kita memilih cakupan pengguna, bukan cakupan skrip.
Gunakan PropertiesService.getUserProperties().setProperty() untuk menyimpan URL spreadsheet. Tambahkan kode berikut ke submitForm di Cards.gs:
PropertiesService.getUserProperties().setProperty('SPREADSHEET_URL',
res['Spreadsheet URL']);
Kemudian, ubah fungsi getSheetUrl di Helpers.gs untuk menampilkan properti yang disimpan sehingga pengguna akan melihat URL terbaru setiap kali mereka menggunakan add-on. Gunakan PropertiesService.getUserProperties().getProperty() untuk mendapatkan nilai properti.
/**
* Determines most recent spreadsheet URL.
* Returns null if no URL was previously submitted.
*
* @returns {String}
*/
function getSheetUrl() {
return PropertiesService.getUserProperties().getProperty('SPREADSHEET_URL');
}
Terakhir, untuk mengakses layanan Properti, skrip juga harus diberi otorisasi. Tambahkan cakupan https://www.googleapis.com/auth/script.storage ke manifes seperti sebelumnya untuk mengizinkan add-on Anda membaca dan menulis informasi properti.
7. Mengurai pesan Gmail
Untuk benar-benar menghemat waktu pengguna, mari kita isi otomatis formulir dengan informasi yang relevan tentang pengeluaran dari email. Kita telah membuat fungsi di Helpers.gs yang memainkan peran ini, tetapi sejauh ini kita hanya menampilkan "TODO" untuk tanggal, jumlah, dan deskripsi pengeluaran.
Misalnya, kita bisa mendapatkan tanggal email diterima dan menggunakannya sebagai nilai default untuk tanggal pengeluaran.
/**
* Determines date the email was received.
*
* @param {Message} message - The message currently open.
* @returns {String}
*/
function getReceivedDate(message) {
return message.getDate().toLocaleDateString();
}
Terapkan dua fungsi yang tersisa:
getExpenseDescriptionmungkin memerlukan penggabungan nama pengirim dan subjek pesan, meskipun ada cara yang lebih canggih untuk mengurai isi pesan dan memberikan deskripsi yang lebih akurat.- Untuk
getLargestAmount, pertimbangkan untuk mencari simbol tertentu yang terkait dengan uang. Kwitansi sering mencantumkan beberapa nilai, seperti pajak dan biaya lainnya. Pikirkan cara Anda dapat mengidentifikasi jumlah yang benar. Ekspresi reguler juga mungkin berguna.
Jika Anda memerlukan inspirasi tambahan, pelajari dokumentasi referensi untuk GmailMessage atau lihat kode solusi yang Anda download di awal codelab. Setelah Anda membuat penerapan sendiri untuk semua fungsi di Helpers.gs, coba gunakan add-on Anda. Buka tanda terima dan mulai mencatatnya dalam spreadsheet.
8. Mengosongkan formulir dengan tindakan kartu
Apa yang terjadi jika Expense It! salah mengidentifikasi pengeluaran dalam email yang terbuka dan mengisi otomatis formulir dengan informasi yang salah? Pengguna menghapus formulir. Class CardAction memungkinkan kita menentukan fungsi yang dipanggil saat tindakan diklik. Mari kita gunakan untuk memberi pengguna cara cepat menghapus formulir.
Ubah createExpensesCard sehingga kartu yang ditampilkan memiliki tindakan kartu berlabel "Hapus formulir" dan saat diklik akan memanggil fungsi clearForm berikut, yang dapat Anda tempel ke Cards.gs. Anda harus meneruskan opt_status sebagai parameter bernama "Status" ke tindakan untuk memastikan bahwa saat formulir dihapus, pesan status tetap ada. Perhatikan bahwa parameter opsional untuk tindakan harus berjenis Object.<string, string>, jadi jika opt_status tidak tersedia, Anda harus meneruskan {'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. Membuat spreadsheet
Selain menggunakan Google Apps Script untuk mengedit spreadsheet yang ada, Anda dapat membuat spreadsheet baru sepenuhnya secara terprogram. Untuk add-on kita, izinkan pengguna membuat spreadsheet untuk pengeluaran. Untuk memulai, tambahkan bagian kartu berikut ke kartu yang ditampilkan 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);
Sekarang, saat pengguna mengklik tombol "Sheet Baru", add-on akan membuat spreadsheet baru yang diformat dengan baris header yang dibekukan sehingga selalu terlihat. Pengguna menentukan judul untuk spreadsheet baru dalam formulir, meskipun menyertakan nilai default jika formulir kosong mungkin merupakan pilihan yang baik. Dalam penerapan createExpensesSheet, tampilkan kartu yang hampir identik dengan kartu yang ada, dengan penambahan pesan status yang sesuai serta pengisian otomatis kolom URL dengan URL spreadsheet baru.
10. Selamat!
Anda telah berhasil mendesain dan menerapkan add-on Gmail yang menemukan pengeluaran dalam email dan membantu pengguna mencatat pengeluaran tersebut ke dalam spreadsheet hanya dalam hitungan detik. Anda telah menggunakan Google Apps Script untuk berinteraksi dengan beberapa Google API dan menyimpan data di antara beberapa eksekusi add-on.
Kemungkinan Peningkatan
Biarkan imajinasi Anda memandu saat Anda meningkatkan kualitas Expense It!, tetapi berikut beberapa ide untuk membuat produk yang lebih berguna:
- Tautkan ke spreadsheet setelah pengguna mencatat pengeluaran
- Menambahkan kemampuan untuk mengedit/mengurungkan pencatatan pengeluaran
- Mengintegrasikan API eksternal untuk memungkinkan pengguna melakukan pembayaran dan meminta uang