Cara Membuat Rekap Iuran Bulanan dan Tunggakan Otomatis dengan Google Apps Script
Bendahara RT sering ditanya hal yang sama setiap bulan: "Bu, saya sudah bayar bulan apa saja ya?" Jawabannya biasanya dicari manual di buku kas atau grup WhatsApp. Padahal kalau data iuran disimpan rapi di Google Sheets, status lunas dan tunggakan tiap warga bisa dihitung otomatis.
Di tutorial ini kita membuat rekap iuran bulanan dengan Google Apps Script: daftar periode otomatis, status lunas per bulan, total tunggakan, dan pencatatan yang tidak bisa dobel. Contohnya diambil dari aplikasi Kas & Iuran Warga yang bisa kamu download gratis di Papicode (link di akhir artikel).
1. Simpan iuran per periode, bukan per tanggal
Kuncinya ada di struktur sheet Iuran. Setiap baris mewakili satu warga untuk satu bulan:
| ID | Tanggal | Kode Warga | Periode | Jumlah | Metode |
|---|---|---|---|---|---|
| IU-01 | 2026-10-03 | W01 | 2026-09 | 50000 | Tunai |
| IU-02 | 2026-10-03 | W01 | 2026-10 | 50000 | Tunai |
Kolom Tanggal adalah kapan uang diterima, sedangkan Periode adalah bulan yang dibayar. Warga yang membayar dua bulan sekaligus di tanggal yang sama jadi dua baris. Dengan begitu, menghitung "bulan mana yang belum dibayar" cukup mencocokkan periode.
Jangan lupa atur kolom ini sebagai teks sebelum menulis data. Kalau tidak, Sheets mengubah 2026-09 menjadi tanggal dan nomor WA 0812... kehilangan angka nol:
sheet.getRange('A:D').setNumberFormat('@');
2. Buat daftar periode otomatis
Simpan bulan mulai di sheet Pengaturan (misalnya 2026-05), lalu buat daftar bulan sampai bulan berjalan:
function daftarPeriode_() {
var mulai = String(bacaPengaturan_().bulan_mulai).slice(0, 7); // "2026-05"
var akhir = Utilities.formatDate(new Date(), 'Asia/Jakarta', 'yyyy-MM');
var y = +mulai.slice(0, 4), m = +mulai.slice(5, 7), out = [];
while (out.length < 120) {
var p = y + '-' + ('0' + m).slice(-2);
if (p > akhir) break; // string "yyyy-MM" bisa dibandingkan langsung
out.push(p);
m++; if (m > 12) { m = 1; y++; }
}
return out; // ["2026-05", "2026-06", ..., "2026-10"]
}
Format yyyy-MM sengaja dipakai karena urutan teksnya sama dengan urutan waktu, jadi p > akhir sudah cukup untuk membandingkan bulan.
3. Hitung lunas dan tunggakan per warga
Kumpulkan periode yang sudah dibayar ke dalam objek, lalu cocokkan dengan daftar periode:
function statusWarga_(w, iuran) {
var bayar = {};
iuran.forEach(function (x) { if (x.kode === w.kode) bayar[x.periode] = x; });
var periode = daftarPeriode_();
var tunggak = periode.filter(function (p) { return !bayar[p]; });
return {
nama: w.nama,
bulan: periode.map(function (p) { return { periode: p, lunas: !!bayar[p] }; }),
tunggakan: tunggak.length,
totalTunggakan: tunggak.length * w.iuran, // iuran bisa beda per warga
};
}
Simpan nominal iuran di sheet Warga (kolom Iuran Khusus). Kalau kosong, pakai nominal default dari Pengaturan. Warga yang punya toko atau rumah kos bisa dikenai iuran berbeda tanpa mengubah kode.
4. Catat beberapa bulan sekaligus tanpa dobel
Bendahara memilih warga dan mencentang bulan yang dibayar. Server harus menolak bulan yang sudah lunas, termasuk ketika dua orang pengurus mencatat bersamaan. Bungkus pengecekan dan penulisan dengan LockService:
function catatIuran(token, data) {
cek_(token);
var lock = LockService.getScriptLock();
lock.waitLock(20000);
try {
var sudah = {};
bacaIuran_().forEach(function (x) { if (x.kode === data.kode) sudah[x.periode] = true; });
var baru = data.periode.filter(function (p) { return !sudah[p]; });
if (!baru.length) throw new Error('Semua bulan yang dipilih sudah lunas.');
var rows = baru.map(function (p, i) { return [idBaru_('IU') + i, hari_(), data.kode, p, data.jumlah, data.metode]; });
sheet.getRange(sheet.getLastRow() + 1, 1, rows.length, rows[0].length).setValues(rows);
.();
{ : baru., : data.. - baru. };
} {
lock.();
}
}
Pakai setValues sekali untuk banyak baris, jangan appendRow di dalam perulangan. Menulis ke Sheets itu lambat, dan satu kali tulis jauh lebih cepat daripada enam kali.
5. Warga cek iuran sendiri dengan aman
Halaman publik tidak boleh membuka data warga ke sembarang orang. Minta 4 digit terakhir nomor WA sebagai "PIN ringan", lalu batasi percobaannya dengan CacheService:
function cekIuran(kode, wa4) {
var cache = CacheService.getScriptCache(), kunci = 'cek_' + kode;
var coba = Number(cache.get(kunci) || 0);
if (coba >= 6) throw new Error('Terlalu banyak percobaan. Coba lagi 15 menit lagi.');
var w = bacaWarga_().filter(function (x) { return x.kode === kode; })[0];
if (!w || w.wa.slice(-4) !== wa4) {
cache.put(kunci, String(coba + 1), 900); // 15 menit
throw new Error('Data tidak cocok.');
}
return statusWarga_(w, bacaIuran_());
}
Satu lagi soal privasi: jangan pernah mengirim nomor WA ke browser. Fungsi untuk halaman publik cukup mengirim kode dan nama warga.
6. Pengingat WhatsApp sekali klik
Untuk warga yang menunggak, buat tautan wa.me dengan pesan yang sudah terisi:
var pesan = 'Assalamualaikum ' + r.nama + ', mengingatkan iuran ada ' + r.tunggakan +
' bulan belum dibayar (' + rp(r.totalTunggakan) + '). Cek status: ' + urlApp;
var link = 'https://wa.me/' + r.wa + '?text=' + encodeURIComponent(pesan);
Tidak perlu API WhatsApp berbayar. Bendahara cukup menekan tombol, WhatsApp terbuka dengan pesan siap kirim.
Ringkasan
- Simpan iuran per warga per periode (
yyyy-MM), pisahkan dari tanggal bayar. - Buat daftar periode otomatis dari bulan mulai sampai bulan berjalan.
- Hitung lunas dan tunggakan dengan mencocokkan periode, dengan nominal per warga.
- Bungkus pencatatan dengan LockService dan lewati bulan yang sudah lunas.
- Cek iuran publik pakai 4 digit WA + batas percobaan, dan jangan kirim nomor WA ke browser.
Download source code lengkapnya
Semua teknik di atas dipakai di Kas & Iuran Warga (Google Apps Script): halaman warga dengan saldo kas, grafik 6 bulan, pengeluaran per pos, dan cek iuran mandiri, plus panel bendahara untuk mencatat iuran dan kas, rekap tunggakan, pengingat WhatsApp, dan laporan Excel. Gratis dan tanpa hosting.
Source code lengkapnya gratis
Lihat semua yang dibahas di artikel ini langsung berjalan.