Cara Membuat Jurnal Mengajar dan Absensi Siswa per Jam dengan Google Apps Script
Jurnal mengajar adalah dokumen yang wajib, tetapi jarang disukai. Buku jurnal kertas sering tertinggal di ruang guru, absensi ditulis ulang di tiga tempat berbeda, dan kepala sekolah baru tahu ada jurnal yang kosong saat supervisi akhir semester.
Di tutorial ini kita membangun inti aplikasi jurnal mengajar dengan Google Apps Script dan Google Sheets: jadwal yang tahu hari, validasi jurnal hanya untuk jadwal milik guru, absensi per jam yang bisa disimpan ulang tanpa data ganda, nilai akhir berbobot, dan laporan keterisian jurnal untuk kepala sekolah. Contohnya diambil dari aplikasi Jurnal Mengajar yang bisa kamu download gratis di Papicode (link di akhir artikel).
1. Jadwal sebagai sumber kebenaran
Semua fitur berputar di sekitar sheet Jadwal: Hari (1 = Senin), Jam Ke (1-2), Kelas, Mapel, dan NIP guru. Untuk menampilkan jadwal hari ini, kita butuh nomor hari dari sebuah tanggal. Utilities.formatDate dengan pola u mengembalikan 1 untuk Senin sampai 7 untuk Minggu, cocok dengan isi sheet:
function hariKe_(tgl) {
return Number(Utilities.formatDate(new Date(tgl + 'T12:00:00+07:00'), 'Asia/Jakarta', 'u'));
}
var slot = bacaJadwal_().filter(function (j) { return j.nip === g.nip && j.hari === hariKe_(tanggal); });
Jam 12:00 dan zona +07:00 ditulis eksplisit supaya hari tidak bergeser walaupun server Google berada di zona lain. Jam pelajaran disimpan sebagai daftar di Pengaturan (07:00-07:40,07:40-08:20,...), lalu "3-4" diterjemahkan menjadi 08:20 - 09:55 dengan mengambil awal jam ke-3 dan akhir jam ke-4.
2. Validasi: jurnal hanya untuk jadwal yang benar
Tanpa validasi, guru bisa (sengaja atau tidak) mengisi jurnal kelas yang tidak diajarnya, atau "menabung" jurnal untuk minggu depan. Satu fungsi kecil memeriksa semuanya:
function cekSlot_(g, tanggal, kelas, jam) {
var hari = hariIni_(), batas = Number(cfg.batas_isi_hari) || 3;
if (tanggal > hari) throw new Error('Jurnal belum bisa diisi untuk tanggal yang akan datang.');
if (tanggal < tambahHari_(hari, -batas)) throw new Error('Jurnal hanya bisa diisi paling lambat ' + batas + ' hari setelah mengajar.');
var j = bacaJadwal_().filter(function (x) {
return x.nip === g.nip && x.hari === hariKe_(tanggal) && x.kelas === kelas && x.jam === jam;
})[0];
if (!j) throw new Error('Tidak ada jadwal mengajar ' + kelas + ' jam ke-' + jam + '.');
return j;
}
Batas beberapa hari memberi kelonggaran (guru sibuk, sinyal jelek), tetapi tetap mendorong jurnal ditulis saat ingatan masih segar. Mapel diambil dari jadwal, bukan dari input browser, sehingga jurnal selalu konsisten.
3. Simpan ulang tanpa data ganda
Guru sering salah ketuk absensi lalu memperbaikinya. Kalau setiap simpan menambah 24 baris absensi baru, data cepat berantakan. Kuncinya: satu jam pelajaran (tanggal + kelas + jam ke) hanya punya satu jurnal. Saat sudah ada, kita perbarui barisnya dan hapus absensi lamanya:
var ada = bacaJurnal_().filter(function (x) { return x.tanggal === tanggal && x.kelas === kelas && x.jam === jam; })[0];
if (ada) {
id = ada.id;
shJ.getRange(ada.baris, 7, 1, 5).setValues([[materi, kegiatan, catatan, String(hadir), kini]]);
bacaAbsen_().filter(function (a) { return a.jurnal === id; })
.sort(function (a, b) { return b.baris - a.baris; }) // hapus dari bawah
.forEach(function (a) { shA.deleteRow(a.baris); });
} else {
id = 'JR-' + acakKode_(6);
shJ.getRange(shJ.getLastRow() + 1, 1, 1, KOL.length).setNumberFormat('@').setValues([[id, tanggal, nip, kelas, mapel, jam, ...]]);
}
shA.(shA.() + , , siswa., ).().(barisAbsen);
Menghapus dari baris paling bawah penting: kalau dihapus dari atas, nomor baris di bawahnya bergeser dan kita bisa menghapus baris yang salah. Seluruh blok dibungkus LockService agar dua penyimpanan bersamaan tidak saling menimpa.
Satu sentuhan kecil yang disukai guru: saat membuka form jam ketiga, siswa yang sudah ditandai sakit atau izin di jam sebelumnya hari itu otomatis ikut ditandai. Guru hanya perlu mengecek, bukan mengulang.
4. Nilai akhir berbobot yang adil di tengah semester
Bobot nilai biasanya Tugas 30%, UH 30%, PTS 20%, PAS 20%. Masalahnya, di bulan Oktober PAS belum ada. Kalau langsung dihitung, semua siswa terlihat tidak tuntas. Solusinya, normalkan bobot hanya dari jenis yang sudah ada nilainya:
function nilaiAkhir_(perJenis, bobot) {
var tot = 0, w = 0;
Object.keys(bobot).forEach(function (j) {
var v = perJenis[j];
if (v && v.length) { tot += bobot[j] * v.reduce(function (a, b) { return a + b; }, 0) / v.length; w += bobot[j]; }
});
return w ? Math.round(tot / w * 10) / 10 : null;
}
nilaiAkhir_({ Tugas: [80, 90], UH: [70] }, { Tugas: 30, UH: 30, PTS: 20, PAS: 20 }); // 77.5
Rata-rata tugas 85 dan UH 70 dengan bobot sama menghasilkan 77,5, bukan 46,5. Saat PTS dan PAS diinput, bobotnya otomatis ikut masuk. Bobot dibaca dari sheet Pengaturan, jadi sekolah yang memakai komposisi lain cukup mengubah satu sel.
5. Keterisian jurnal untuk kepala sekolah
Laporan paling berguna bagi kepala sekolah bukan daftar jurnal, melainkan berapa persen jam mengajar yang sudah dijurnal. Kita jalan dari tanggal awal sampai akhir periode, mencocokkan setiap jadwal pada hari itu dengan jurnal yang ada:
var wajib = {}, isi = {}, tgl = dari;
while (tgl <= sampai) {
var hk = hariKe_(tgl), t = tgl;
jadwal.filter(function (j) { return j.hari === hk; }).forEach(function (j) {
wajib[j.nip] = (wajib[j.nip] || 0) + 1;
if (jurnal.some(function (x) { return x.tanggal === t && x.kelas === j.kelas && x.jam === j.jam; })) isi[j.nip] = (isi[j.nip] || 0) + 1;
});
tgl = tambahHari_(tgl, 1);
}
Dari dua angka itu lahir persentase per guru. Untuk hari ini, kita juga mencari jam pelajaran yang sudah lewat tetapi belum dijurnal, lalu menampilkan tombol WhatsApp berisi pengingat sopan. Jam yang belum selesai tidak ikut dihitung, supaya guru tidak ditegur untuk kelas yang masih berlangsung.
Ringkasan
- Jadikan sheet Jadwal sumber kebenaran; pakai pola
uuntuk nomor hari. - Validasi jurnal: milik guru sendiri, hari yang cocok, bukan tanggal depan, dalam batas hari.
- Satu jam pelajaran satu jurnal; simpan ulang memperbarui dan mengganti absensi, hapus baris dari bawah.
- Normalkan bobot nilai agar nilai akhir masuk akal sebelum semua penilaian ada.
- Hitung keterisian dengan mencocokkan jadwal per tanggal dengan jurnal.
Download source code lengkapnya
Versi lengkapnya sudah termasuk login guru dengan NIP + PIN, absensi sekali ketuk, input nilai dengan penanda KKM, rekap kelas, riwayat jurnal, dashboard kepala sekolah dengan pengingat WhatsApp, daftar siswa sering alpa, dan ekspor CSV. Semua berjalan di Google Sheets tanpa hosting.
Source code lengkapnya gratis
Lihat semua yang dibahas di artikel ini langsung berjalan.
Tutorial lainnya
Cara Membuat Sistem Tiket Travel dengan Pilih Kursi di Google Apps Script: Layout Armada, Anti Kursi Dobel, dan Kursi Kedaluwarsa
20 Oktober 2026
Cara Membuat Website Donasi Transparan dengan Google Apps Script: Kode Unik Transfer dan Laporan Penyaluran
20 Oktober 2026