Cara Membuat Website Donasi Transparan dengan Google Apps Script: Kode Unik Transfer dan Laporan Penyaluran
Masalah terbesar penggalangan dana komunitas bukan teknis, melainkan kepercayaan. Donatur ingin tahu uangnya benar-benar sampai, sementara pengurus kewalahan mencocokkan puluhan transfer Rp100.000 yang masuk di hari yang sama tanpa tahu mana milik siapa. Akhirnya laporan dibuat seadanya di grup WhatsApp, lalu tenggelam.
Di tutorial ini kita membangun inti website donasi transparan dengan Google Apps Script dan Google Sheets: kode unik transfer yang tidak bentrok, donasi tertunda yang kedaluwarsa, saldo program yang dihitung dari data mentah, penyaluran yang tidak bisa melebihi saldo, dan data publik yang menjaga privasi donatur. Contohnya diambil dari aplikasi Donasi Transparan yang bisa kamu download gratis di Papicode (link di akhir artikel).
1. Kode unik: cara sederhana mengenali transfer
Tanpa payment gateway, cara paling praktis mengenali transfer adalah menambahkan angka kecil di belakang nominal. Donatur memilih Rp100.000, sistem meminta transfer Rp100.162. Di mutasi rekening, angka 162 itu seperti tanda tangan.
Kuncinya: kode tidak boleh sama dengan donasi lain yang masih menunggu dengan nominal yang sama. Dua donasi Rp100.162 akan membuat pengurus bingung lagi.
var dipakai = {};
semua.forEach(function (d) {
if (d.status === 'Menunggu' && !kedaluwarsa_(d, cfg) && d.nominal === nominal) dipakai[d.unik] = 1;
});
var unik = 0, coba = 0;
do { unik = 1 + Math.floor(Math.random() * 999); } while (dipakai[unik] && ++coba < 3000);
if (dipakai[unik]) throw new Error('Sedang banyak donasi dengan nominal yang sama. Coba ubah nominal sedikit.');
Pengecekan ini berada di dalam LockService.getScriptLock(). Tanpa kunci, dua donatur yang menekan tombol pada detik yang sama bisa mendapat kode yang sama. Kode unik juga ikut dicatat sebagai donasi, jadi tidak ada selisih antara mutasi rekening dan laporan.
2. Donasi tertunda yang kedaluwarsa sendiri
Banyak orang mengisi form lalu batal transfer. Kalau donasi seperti ini dibiarkan menunggu selamanya, kode unik makin cepat habis dan daftar verifikasi penuh sampah. Kita tidak perlu trigger terjadwal; cukup hitung saat dibaca:
function waktuMs_(s) { return new Date(String(s).replace(' ', 'T') + ':00+07:00').getTime(); }
function kedaluwarsa_(d, cfg) {
return d.status === 'Menunggu' && Date.now() - waktuMs_(d.waktu) > Number(cfg.batas_bayar_jam || 48) * 3600000;
}
Donasi kedaluwarsa tidak lagi memblok kode unik dan tampil pudar di panel pengurus. Jika transfernya ternyata masuk terlambat, pengurus tetap bisa menerimanya. Tidak ada data yang hilang, hanya statusnya yang dihitung ulang.
3. Saldo dihitung, bukan disimpan
Godaan pertama adalah membuat kolom "Terkumpul" di sheet Program dan menambahkannya setiap verifikasi. Masalahnya, satu salah ketik membuat angka itu selamanya tidak cocok dengan rincian. Untuk aplikasi yang menjual transparansi, angka harus bisa ditelusuri ke baris aslinya:
function rekapProgram_(p, don, sal, hari) {
var masuk = don.filter(function (d) { return d.prog === p.kode && d.status === 'Diterima'; });
var keluar = sal.filter(function (s) { return s.prog === p.kode; });
var terkumpul = masuk.reduce(function (a, d) { return a + d.total; }, 0);
var salur = keluar.reduce(function (a, s) { return a + s.jumlah; }, 0);
var aktif = p.status === 'Aktif' && (!p.deadline || p.deadline >= hari);
return { terkumpul: terkumpul, tersalur: salur, saldo: terkumpul - salur, donatur: masuk.length,
persen: p.target ? Math.min(100, Math.round(terkumpul / p.target * )) : , : aktif };
}
Fungsi yang sama dipakai di kartu program, halaman detail, tabel saldo publik, dan panel pengurus. Status "selesai" pun dihitung: program yang melewati deadline otomatis berhenti menerima donasi tanpa pengurus harus mengubah apa pun.
4. Penyaluran tidak boleh melebihi saldo
Sisi keluar sama pentingnya. Setiap penyaluran dicatat dengan tanggal, judul, jumlah, keterangan, dan link bukti. Server menolak penyaluran yang lebih besar dari saldo program dan tanggal di masa depan:
if (!/^\d{4}-\d{2}-\d{2}$/.test(tgl) || tgl > hariIni_()) throw new Error('Tanggal penyaluran tidak valid.');
if (bukti && !/^https:\/\/[^\s"'<>]{4,300}$/.test(bukti)) throw new Error('Link bukti wajib diawali https://.');
var r = rekapProgram_(p, bacaDonasi_(), bacaSalur_(), hariIni_());
if (jumlah > r.saldo) throw new Error('Melebihi saldo program (' + rp_(r.saldo) + ').');
Pembatasan link ke https:// bukan sekadar kerapian. Link bukti ditampilkan di halaman publik sebagai tautan, dan tanpa validasi seseorang dengan akses pengurus bisa menyisipkan javascript: yang berjalan saat pengunjung mengklik.
5. Data publik dengan prinsip allowlist
Halaman publik menampilkan nama donatur dan doanya, karena itu memberi semangat dan bukti sosial. Tapi nomor WhatsApp harus tetap privat, dan donatur yang memilih anonim tidak boleh terlihat namanya. Cara paling aman adalah membangun objek baru yang hanya berisi field yang boleh keluar:
function donaturPublik_(d) {
return { nama: d.anonim ? 'Hamba Allah' : d.nama, nominal: d.nominal, pesan: d.pesan, waktu: d.verif || d.waktu };
}
Bandingkan dengan menghapus field sensitif dari objek asli: suatu hari kamu menambah kolom baru (misalnya email) dan lupa menghapusnya, lalu kolom itu bocor ke seluruh internet. Dengan allowlist, kolom baru tidak akan pernah keluar sampai kamu sengaja menambahkannya.
Cek status donasi juga memakai faktor kedua: kode donasi ditambah 4 digit terakhir nomor HP, dengan batas enam percobaan per 15 menit.
Ringkasan
- Kode unik 1-999 dipilih di dalam LockService dan tidak bentrok dengan donasi menunggu bernominal sama.
- Donasi tertunda kedaluwarsa dengan perhitungan saat baca, tanpa trigger.
- Saldo, persentase, dan status program dihitung dari baris donasi dan penyaluran.
- Penyaluran dibatasi saldo, tanggal tidak boleh di masa depan, link bukti wajib https.
- Data publik dibangun dengan allowlist; donatur anonim tampil sebagai Hamba Allah.
Download source code lengkapnya
Versi lengkapnya sudah termasuk halaman depan bergaya zine dengan teks berjalan donatur, halaman detail program, form donasi dengan tombol salin rekening, grafik dana masuk dan keluar, tabel saldo, panel pengurus dengan pencocokan mutasi, donasi tunai, ucapan terima kasih WhatsApp, dan ekspor CSV. Semua berjalan di Google Sheets tanpa hosting.
Source code lengkapnya gratis
Lihat semua yang dibahas di artikel ini langsung berjalan.