Seluruh sembilan bagian sebelumnya bermuara pada satu dokumen: laporan akhir. Laporan ini ditujukan kepada Bu Rina, bukan kepada sesama programmer, sehingga bentuknya teks datar tanpa kode — bisa dibuka di ponsel, dicetak, atau ditempel di dinding belakang kasir. Pada bagian ini kita membedah struktur laporan tersebut, memeriksa ulang bahwa setiap angkanya memang berasal dari data, lalu menutup proyek dengan refleksi: apa yang akan kita lakukan berbeda bila proyek ini diulang. Prinsip penulisannya mengikuti chapter Membuat Laporan untuk Non-Teknis dan Menyusun Ringkasan Eksekutif .

Struktur Lima Bagian Laporan #

Laporan akhir tersusun atas lima bagian berurutan, masing-masing dengan tugas yang jelas:

BagianIsiSumbernya dari
1. Ringkasan EksekutifKesimpulan utama dalam empat paragraf pendekseluruh analisis
2. Temuan UtamaEmpat temuan T1-T4 dengan angkanyaBagian 7 dan 9
3. Angka KunciTujupat baris angka penting siap salinBagian 6 dan 7
4. RekomendasiEmpat tindakan R1-R4 beserta alasan angkanyaBagian 9
5. Catatan Kualitas DataJujur mencatat pembersihan dan keterbatasanBagian 4 dan 5

Urutan ini disengaja: pembaca sibuk cukup membaca bagian 1 untuk mengerti semuanya, dan semakin jauh dibaca semakin teknis detailnya. Karena laporan ditulis oleh skrip analisis_penjualan.py — bukan diketik tangan — strukturnya bisa kita periksa langsung dari berkasnya:

python
with open("../laporan/laporan-akhir.txt", encoding="utf-8") as berkas:
    baris_laporan = berkas.read().splitlines()

print(f"Jumlah baris laporan : {len(baris_laporan)}")
print("\nStruktur laporan:")
for baris in baris_laporan:
    if baris[:1].isdigit() and ". " in baris[:4]:
        print(" ", baris)

Output yang Dihasilkan:

text
Jumlah baris laporan : 79

Struktur laporan:
  1. RINGKASAN EKSEKUTIF
  2. TEMUAN UTAMA
  3. ANGKA KUNCI
  4. REKOMENDASI
  5. CATATAN KUALITAS DATA

Mari kita bedah kode kecil di atas:

  1. open(...).read().splitlines(): seluruh isi laporan dibaca sekali lalu dipecah menjadi daftar baris, sehingga struktur bisa diperiksa tanpa mencetak 79 baris penuh.
  2. Syarat baris[:1].isdigit() and ". " in baris[:4]: hanya baris yang diawali angka lalu titik (seperti 2. TEMUAN UTAMA) yang dicetak. Baris bertanda T1 atau R1 tidak ikut karena tidak diawali angka — hasilnya persis daftar isi laporan.
  3. 79 baris: cukup ringkas untuk dicetak satu lembar; angka ini juga menegaskan bahwa laporan memang ditulis ulang setiap kali skrip dijalankan, bukan berkas tinggalan.

Membaca Ringkasan Eksekutif #

Bagian pembuka laporan adalah contoh bagaimana angka analisis diterjemahkan menjadi kalimat yang bisa dibaca siapa pun. Berikut potongannya:

text Potongan laporan-akhir.txt, bagian 1
1. RINGKASAN EKSEKUTIF
----------------------------------------------------------------
Sepanjang 5-16 Januari 2026, Toko Kopi Kita membukukan pendapatan
total Rp 23.649.000 dari 1.184 gelas terjual.
kopi susu menjadi menu penopang dengan kontribusi
42,7% dari total pendapatan.
Rata-rata pendapatan akhir pekan Rp 2.829.000
per hari, 57,2% di atas rata-rata hari kerja
Rp 1.799.100.
Rabu 14 Januari menjadi hari tersepi
(Rp 903.000, 45,8% dari rata-rata harian)
setelah hujan deras seharian menurut catatan Bu Rina.

Perhatikan tiga sifat ringkasan tersebut. Pertama, setiap kalimat memuat angka — total pendapatan, kontribusi 42,7%, rasio 57,2% — sehingga tidak ada klaim yang menggantung. Kedua, satuan ditulis lengkap (rupiah penuh, bukan kode pendapatan_ribu), dan angka mengikuti format Indonesia. Ketiga, konteks non-data (hujan deras) ditulis apa adanya beserta sumbernya (“menurut catatan Bu Rina”) supaya pembaca tahu mana kesimpulan dari data dan mana keterangan tambahan.

Mengunduh Laporan Lengkap #

Laporan utuh 79 baris tersedia sebagai berkas laporan/laporan-akhir.txt pada proyek ini, dan dapat Anda unduh dari halaman overview proyek — tautan unduhnya tampil pada kepala blok laporan di halaman tersebut. Skrip src/analisis_penjualan.py yang menghasilkan laporan juga tersedia di bagian Berkas Sumber di bawah setiap halaman bagian, jadi Anda bisa mengunduh ketiga berkas (data mentah, skrip, laporan) sekaligus dan menjalankan ulang seluruh alurnya dengan satu perintah python3 src/analisis_penjualan.py. Inilah alur lengkap dari data mentah hingga dokumen siap baca: data mentah diperiksa, dibersihkan, dianalisis, lalu laporannya ditulis ulang oleh skrip — bukan disalin dari hasil sebelumnya.

Memeriksa Ulang Angka Laporan #

Bagian penutup laporan menyatakan bahwa seluruh angkanya dapat direproduksi. Klaim seperti itu memang harusnya bisa diuji, bukan sekadar dipercaya. Kita hitung ulang dua angka penting langsung dari data bersih, lalu periksa apakah sebutannya memang tersurat di berkas laporan:

python
import pandas as pd


def muat_bersih(path):
    """Muat data mentah dan terapkan pembersihan hasil Bagian 5."""
    df = pd.read_csv(path).drop_duplicates().reset_index(drop=True)
    df["menu"] = df["menu"].str.lower()
    df["gelas"] = pd.to_numeric(df["gelas"].replace("-", pd.NA))
    valid = df[df["gelas"].notna() & (df["pendapatan_ribu"] > 0)]
    harga = (valid["pendapatan_ribu"] / valid["gelas"]).groupby(valid["menu"]).median()
    nol = df["pendapatan_ribu"] == 0
    df.loc[nol, "pendapatan_ribu"] = (
        df.loc[nol, "gelas"] * df.loc[nol, "menu"].map(harga)
    ).astype(int)
    kosong = df["gelas"].isna()
    df.loc[kosong, "gelas"] = (
        df.loc[kosong, "pendapatan_ribu"] / df.loc[kosong, "menu"].map(harga)
    )
    df["gelas"] = df["gelas"].astype(int)
    return df


bersih = muat_bersih("../data/penjualan_kotor.csv")

total_ribu = int(bersih["pendapatan_ribu"].sum())
per_menu = bersih.groupby("menu")["pendapatan_ribu"].sum().sort_values(ascending=False)
kontribusi = f"{100 * per_menu.iloc[0] / per_menu.sum():.1f}%".replace(".", ",")

with open("../laporan/laporan-akhir.txt", encoding="utf-8") as berkas:
    isi_laporan = berkas.read()

sebutan_total = "Rp " + f"{total_ribu * 1000:,}".replace(",", ".")
print(f"Hitungan ulang dari data bersih : {total_ribu} ribu rupiah ({sebutan_total})")
print(f"Tersurat di laporan             : {sebutan_total in isi_laporan}")
print(f"Kontribusi kopi susu            : {kontribusi}")
print(f"Tersurat di laporan             : {kontribusi in isi_laporan}")

Output yang Dihasilkan:

text
Hitungan ulang dari data bersih : 23649 ribu rupiah (Rp 23.649.000)
Tersurat di laporan             : True
Kontribusi kopi susu            : 42,7%
Tersurat di laporan             : True

Cara kerja pemeriksaannya sederhana namun kuat:

  1. Hitung ulang, jangan percaya: total pendapatan dihitung dari data bersih (23.649 ribu), lalu diformat menjadi Rp 23.649.000 — format yang sama dengan yang dipakai laporan.
  2. sebutan_total in isi_laporan: operator in memeriksa apakah string itu benar-benar muncul di dalam teks laporan. Hasil True berarti angka pada laporan cocok dengan hitungan ulang; hasil False berarti laporan dan data sudah tidak sejajar — sinyal untuk menyusun ulang laporan.
  3. Kontribusi ikut diperiksa: 42,7% (koma desimal Indonesia) juga ditemukan tersurat. Dua-duanya benar, jadi klaim keterulangan di halaman penutup laporan terbukti.

Refleksi Proyek #

Proyek pertama ini selesai, dan nilainya justru bertambah bila kita jujur menilai apa yang bisa lebih baik. Lima hal berikut akan kami lakukan berbeda bila proyek diulang:

  1. Mencatat cuaca sejak awal. Anomali 14 Januari akhirnya dijelaskan oleh cerita hujan deras Bu Rina, bukan oleh data. Satu kolom cuaca pada ekspor kasir akan mengubah penjelasan itu dari dugaan menjadi bukti.
  2. Menggunakan periode lebih panjang. Rasio akhir pekan 1,57 berdiri di atas rata-rata dua hari saja. Dengan tiga bulan data, tiap kelompok memuat belasan hari dan kesimpulannya jauh lebih kokoh.
  3. Memperbaiki kebiasaan input di hulu. Dua baris duplikat, tiga sel kosong, satu nama menu kapital, dan satu pendapatan nol — semuanya bisa dicegah di aplikasi kasir. Pembersihan tetap perlu dikuasai, tetapi data yang bersih sejak awal membuat proyek bergerak lebih cepat.
  4. Mencatat jam transaksi. Data harian tidak bisa menjawab “jam berapa yang paling ramai” — pertanyaan yang sangat menentukan jadwal pegawai. Kolom waktu akan menjadi pertanyaan pertama yang kami minta pada proyek berikutnya.
  5. Menyimpan log pembersihan di dalam skrip. Kebiasaan ini sudah terwujud pada analisis_penjualan.py lewat kamus perbaikan, dan akan terus dipertahankan: setiap perubahan pada data punya jejak yang bisa diperiksa.

Refleksi di atas bukan daftar penyesalan, melainkan daftar permintaan data yang lebih tajam untuk putaran berikutnya.

Dari keluhan “sepertinya Sabtu ramai” hingga laporan 79 baris yang setiap angkanya bisa diuji, kita telah menuntaskan satu putaran penuh siklus data: memahami masalah, bertanya, mengumpulkan, memvalidasi, membersihkan, mengeksplorasi, menganalisis, memvisualkan, menyusun temuan, dan melaporkan. Keahlian yang sama akan terus terpakai — dengan data dan tantangan yang berbeda — pada proyek berikutnya: Proyek: Analisis Harga Komoditas .