Tugas UTS

Tugas UTS
Programming Financial Bot

Tugas Proyek Akhir: Membangun Bot Telegram Manajemen Keuangan

Integrasi Financial Technology (Fintech) Menggunakan Google Apps Script

šŸŽÆ Tujuan Pembelajaran

Seorang manajer keuangan modern harus melek teknologi. Pada tugas ini, Anda akan mempraktikkan langsung bagaimana membangun sistem pencatatan keuangan pribadi otomatis. Kita akan menyulap Google Sheets sebagai Database (buku besar), Google Apps Script sebagai Otak Pemroses, dan Telegram sebagai Kasir/Antarmuka.

Tahap 1: Membuat Database (Google Sheets)

Langkah pertama adalah menyiapkan buku catatan digital kita.

  1. Buka Google Sheets dan buat *Spreadsheet* kosong baru. Beri nama file: "Database Keuangan Bot".
  2. Ubah nama Sheet1 di bagian bawah menjadi transaksi (huruf kecil semua).
  3. Pada baris pertama (A1 sampai I1), ketikkan Header kolom berikut secara berurutan:
    User_id | Nama | ID | Tanggal | Jenis | Kategori | Jumlah | Keterangan | Sumber
  4. Buat satu *Sheet* baru lagi (klik tombol + di kiri bawah), beri nama log_error.
  5. Pada baris pertama log_error, buat Header:
    Timestamp | Error Message | Raw Text | Chat ID
  6. SANGAT PENTING: Perhatikan URL *Spreadsheet* Anda di atas (Address bar browser). Salin kode panjang di antara /d/ dan /edit. Itu adalah SPREADSHEET_ID Anda. Simpan di Notepad!

Tahap 2: Membuat "Kasir" di Telegram

Kita butuh robot (bot) untuk menerima pesan dari Anda di Telegram.

  • Buka aplikasi Telegram Anda, cari akun bernama @BotFather (dengan centang biru).
  • Kirim pesan: /newbot
  • Ikuti instruksinya: Masukkan nama bot Anda (misal: "Keuangan Mahasiswa"), lalu masukkan username bot yang diakhiri kata 'bot' (misal: keuangan_aku_bot).
  • Jika berhasil, BotFather akan memberikan TOKEN API (Bentuknya panjang, contoh: 8433576518:AAGBcPB...). Salin Token tersebut dan simpan di Notepad!

Tahap 3: Menanamkan "Otak" (Google Apps Script)

Kembali ke file Google Sheets Anda.

  1. Klik menu Ekstensi (Extensions) > Apps Script.
  2. Sebuah tab baru akan terbuka. Hapus semua tulisan bawaan function myFunction()....
  3. Salin seluruh Source Code (SC) di dalam kotak hitam di bawah ini, dan tempel (paste) ke layar Apps Script Anda:
// --- BAGIAN YANG WAJIB DIUBAH ---
const TOKEN = "MASUKKAN_TOKEN_BOTFATHER_ANDA_DI_SINI";
const SPREADSHEET_ID = "MASUKKAN_ID_SPREADSHEET_ANDA_DI_SINI";
// --------------------------------

// ==========================
// MAIN HANDLER (Penerima Pesan)
// ==========================
function doPost(e) {
  const data = JSON.parse(e.postData.contents);
  const message = data.message;

  if (!message || !message.text) return;

  const chatId = message.chat.id;
  const nama = message.from.first_name || "User";
  const text = message.text;

  try {
    if (text.startsWith("/add")) {
      handleAdd(text, chatId, nama);
    } else if (text.startsWith("/saldo")) {
      handleSaldo(chatId);
    } else if (text.startsWith("/report")) {
      handleReport(chatId);
    } else {
      sendMessage(chatId, "Perintah tidak dikenali. Coba /add, /saldo, atau /report.");
    }
  } catch (err) {
    logError(err, text, chatId);
    sendMessage(chatId, "Terjadi error pada sistem.");
  }
}

// ==========================
// ADD TRANSAKSI (Fungsi Catat)
// ==========================
function handleAdd(text, chatId, nama) {
  const parts = text.split(" ");
  const jenis = parts[1] ? parts[1].toLowerCase().trim() : null;
  const kategori = parts[2];
  const jumlahRaw = parts[3] ? parts[3].replace(/\./g, "") : "";
  const jumlah = parseInt(jumlahRaw);
  const keterangan = parts.slice(4).join(" ");

  if (!jenis || (jenis !== "pemasukan" && jenis !== "pengeluaran") || !kategori || isNaN(jumlah)) {
    sendMessage(chatId, "Format Salah!\n\nKetik:\n/add pengeluaran makan 20000 nasi padang\n(Jangan gunakan titik pada angka)");
    return;
  }

  const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName("transaksi");
  const id = "TRX" + Utilities.formatString("%04d", sheet.getLastRow());
  const tanggal = new Date();

  sheet.appendRow([chatId, nama, id, tanggal, jenis, kategori, jumlah, keterangan, "telegram"]);
  sendMessage(chatId, `āœ… Data ${jenis} sebesar Rp ${jumlah} berhasil disimpan ke Database!`);
}

// ==========================
// SALDO PER USER (Fungsi Hitung)
// ==========================
function handleSaldo(chatId) {
  const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName("transaksi");
  const data = sheet.getDataRange().getValues();
  let pemasukan = 0, pengeluaran = 0;

  for (let i = 1; i < data.length; i++) {
    if (data[i][0] == chatId) {
      const jenis = data[i][4] ? data[i][4].toString().toLowerCase().trim() : "";
      const jumlah = Number(data[i][6]) || 0;
      if (jenis === "pemasukan") pemasukan += jumlah;
      if (jenis === "pengeluaran") pengeluaran += jumlah;
    }
  }

  const saldo = pemasukan - pengeluaran;
  sendMessage(chatId, `šŸ’° **Informasi Saldo:**\n\nTotal Pemasukan: Rp ${pemasukan}\nTotal Pengeluaran: Rp ${pengeluaran}\n\nšŸ“ˆ Sisa Saldo: Rp ${saldo}`);
}

// ==========================
// REPORT BULANAN
// ==========================
function handleReport(chatId) {
  const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName("transaksi");
  const data = sheet.getDataRange().getValues();
  const now = new Date();
  const bulan = now.getMonth(), tahun = now.getFullYear();
  let pemasukan = 0, pengeluaran = 0;

  for (let i = 1; i < data.length; i++) {
    if (data[i][0] == chatId) {
      const tanggalRaw = data[i][3];
      let tanggal = (tanggalRaw instanceof Date) ? tanggalRaw : new Date(tanggalRaw);
      
      if (isNaN(tanggal.getTime())) continue; 

      if (tanggal.getMonth() === bulan && tanggal.getFullYear() === tahun) {
        const jenis = data[i][4] ? data[i][4].toString().toLowerCase().trim() : "";
        const jumlah = Number(data[i][6]) || 0;
        if (jenis === "pemasukan") pemasukan += jumlah;
        if (jenis === "pengeluaran") pengeluaran += jumlah;
      }
    }
  }
  sendMessage(chatId, `šŸ“Š Laporan Bulan Ini\n\nšŸ’° Pemasukan: Rp ${pemasukan}\nšŸ’ø Pengeluaran: Rp ${pengeluaran}\nšŸ“ˆ Saldo: Rp ${pemasukan - pengeluaran}`);
}

// ==========================
// API SENDER & ERROR LOGGER
// ==========================
function sendMessage(chatId, text) {
  const url = `https://api.telegram.org/bot${TOKEN}/sendMessage`;
  UrlFetchApp.fetch(url, {
    method: "post", contentType: "application/json",
    payload: JSON.stringify({ chat_id: chatId, text: text })
  });
}

function logError(err, raw, chatId) {
  const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName("log_error");
  sheet.appendRow([new Date(), err.toString(), raw, chatId]);
}

Aksi Wajib di Apps Script: Pada Baris 2 dan 3 di kode atas, Anda WAJIB mengganti teks di dalam tanda kutip dengan TOKEN BotFather dan SPREADSHEET_ID milik Anda yang tadi disimpan di Notepad. Jika tidak, bot tidak akan bisa menyala!

Setelah diubah, klik tombol Simpan (Ikon Disket) di menu atas.

Tahap 4: Mengaktifkan Bot (Deploy & Webhook)

Kode sudah siap, kini saatnya menghubungkan server Google dengan server Telegram.

  1. Di layar Apps Script, klik tombol biru Terapkan (Deploy) di pojok kanan atas > Pilih Deployment Baru.
  2. Klik ikon roda gigi (āš™ļø) di sebelah kiri > Pilih Aplikasi Web (Web App).
  3. Pada kolom deskripsi, isi "Versi 1".
  4. Pada opsi Siapa yang memiliki akses (Who has access), WAJIB ubah menjadi: Siapa saja (Anyone).
  5. Klik Terapkan. Jika muncul peringatan keamanan, klik "Tinjau Izin" > Pilih akun Google Anda > Klik tulisan kecil Advanced (Lanjutan) > Klik tulisan paling bawah "Go to project (Buka proyek/Tidak aman)" > Klik Izinkan (Allow).
  6. Akan muncul URL Aplikasi Web (Web App URL). Salin link panjang tersebut ke Notepad.
  7. Langkah Terakhir (Webhook): Buka tab Browser (Chrome/Firefox) baru. Ketik rumus tautan berikut di kolom alamat/URL atas layar Anda:
    https://api.telegram.org/bot[TOKEN_ANDA]/setWebhook?url=[URL_WEBAPP_ANDA] (Ganti [TOKEN_ANDA] dan [URL_WEBAPP_ANDA] dengan data milik Anda, TANPA tanda kurung siku). Lalu tekan ENTER.
  8. Jika di layar muncul tulisan "ok":true,"description":"Webhook was set", artinya BOT ANDA SUDAH HIDUP!

šŸš€ Tahap 5: Pengujian & Syarat Pengumpulan Tugas

Buka aplikasi Telegram, cari Bot yang baru Anda buat, klik START, dan lakukan 4 pengujian ini:

  • Input Modal: /add pemasukan modal 500000 setoran investasi awal
  • Input Biaya: /add pengeluaran bensin 25000 beli pertamax
  • Cek Sisa Uang: /saldo
  • Cek Rekap Bulan: /report

Format Pengumpulan:

Silakan Screenshot (Tangkap Layar) bukti percakapan Telegram yang berhasil dibalas oleh Bot, beserta Screenshot Google Sheets Anda yang sudah terisi otomatis. Kumpulkan dalam bentuk PDF ke portal tugas kelas.

⭐ Tantangan Pengembangan Usaha (Nilai Plus A)

Sistem yang kita buat di atas masih sangat terbuka. Siapapun yang tahu username Bot Anda, bisa ikut memasukkan data ke Spreadsheet Anda. Sebagai Manajer Keuangan, Keamanan Data (Data Security) adalah prioritas utama.

Tantangan Anda: Modifikasilah Source Code (SC) di Tahap 3, khususnya pada fungsi doPost(e). Tambahkan logika validasi chatId menggunakan fungsi "IF". Jika pesan datang dari chatId yang BUKAN milik Anda, bot harus menolak dengan membalas: "Akses Ditolak! Anda bukan pemilik rekening ini."

Gunakan Google untuk mencari tahu bagaimana cara mencocokkan Chat ID di Apps Script!