From e5d45cdcddda11bc9d42a52926769a62c5a99b47 Mon Sep 17 00:00:00 2001 From: Power BI Dev Date: Sun, 9 Aug 2026 20:29:15 +0700 Subject: [PATCH] Peringatan kalau bobot komponen RPS terisi tapi Sub-CPMK-nya belum dicentang Kasus nyata: RPS bagian G bobotnya sudah lengkap (total 100%), tapi kolom "Sub-CPMK yang Dinilai" tak satu pun dicentang di tiap komponen. Komponen begini lolos validasi total bobot, tapi _komponen_daftar() menyaringnya habis (butuh subs DAN bobot) -- dosen jadi bingung kenapa halaman Nilai sama sekali tak punya section "ISI PER KOMPONEN", padahal RPS-nya sudah diisi. - _komponen_tanpa_sub(): fungsi baru, deteksi komponen dengan bobot > 0 tapi subs kosong - Halaman RPS: peringatan di atas tabel bagian G, sebut nama komponen yang bermasalah - Halaman Nilai: peringatan serupa + link "Buka RPS" -- muncul di titik gejalanya, bukan cuma di sumbernya Co-Authored-By: Claude Sonnet 5 --- app/main.py | 19 +++++++++++++++++++ app/templates/form_nilai.html | 7 +++++++ app/templates/form_rps.html | 6 ++++++ 3 files changed, 32 insertions(+) diff --git a/app/main.py b/app/main.py index aba9c35..ea77ae6 100644 --- a/app/main.py +++ b/app/main.py @@ -327,6 +327,19 @@ def _normalisasi_komponen(tersimpan: list[dict]) -> list[dict]: return out +def _komponen_tanpa_sub(rps_data: dict) -> list[str]: + """Nama komponen RPS bagian G yang bobotnya sudah diisi tapi belum ada + Sub-CPMK dicentang. Komponen begini masih ikut dihitung ke total 100% di + bagian G (jadi mudah lolos tanpa disadari), tapi disaring habis oleh + _komponen_daftar() — tidak akan pernah muncul di halaman Nilai.""" + out = [] + for k in _normalisasi_komponen(rps_data.get("komponen", [])): + bobot_terisi = str(k.get("bobot") or "").strip() not in ("", "0", "0.0") + if bobot_terisi and not k.get("subs"): + out.append(k["nama"]) + return out + + def minggu_default() -> list[dict]: rows = [] for w in range(1, 17): @@ -456,6 +469,7 @@ def form_rps(request: Request, kode: str, pesan: str = ""): f.setdefault("referensi_teks", "\n".join(f.get("referensi", []))) f["komponen"] = _normalisasi_komponen(f.get("komponen", [])) ctx_status = tersimpan + komponen_tanpa_sub = _komponen_tanpa_sub(f) else: f = form_kosong() # prefill SKS & semester dari data kurikulum (sheet '14. Susunan MK') @@ -465,6 +479,7 @@ def form_rps(request: Request, kode: str, pesan: str = ""): if info.get("semester"): f["identitas"]["semester"] = str(info["semester"]) ctx_status = {"status": "", "updated_at": "", "updated_by": ""} + komponen_tanpa_sub = [] # form belum pernah disimpan — bobot masih bawaan default peta = _terapkan_override_sub(peta, f) return render( request, "form_rps.html", @@ -473,6 +488,7 @@ def form_rps(request: Request, kode: str, pesan: str = ""): "tahun": db.tahun_aktif(), "pesan": pesan, "boleh_edit": boleh_rps(request.state.user, kode), "tahun_lain": db.tahun_rps_lain(kode) if not tersimpan else [], + "komponen_tanpa_sub": komponen_tanpa_sub, "sub_uraian": {s["kode"]: s["uraian"] for s in peta["subs"]}}, ) @@ -946,6 +962,8 @@ def _konteks_nilai(request, kode, pesan="", peringatan=None): terdaftar = db.mahasiswa_mk(kode) grid = _grid_mahasiswa(tersimpan, terdaftar, kelas_dosen) komponen_daftar = _komponen_daftar(kode) + rps_cek = db.ambil_rps(kode) + komponen_tanpa_sub = _komponen_tanpa_sub(rps_cek["data"]) if rps_cek else [] sesi_semua = (tersimpan["data"].get("sesi") or {}) if tersimpan else {} bobot_komponen, bobot_sub_rincian = _rincian_bobot(kode) # Nilai Akhir dihitung hanya dari Sub-CPMK yang sudah ternilai (lihat @@ -983,6 +1001,7 @@ def _konteks_nilai(request, kode, pesan="", peringatan=None): "grid": grid, "kelas_dosen": kelas_dosen, "tidak_lengkap": tidak_lengkap, "dikatrol": dikatrol, "komponen_daftar": komponen_daftar, + "komponen_tanpa_sub": komponen_tanpa_sub, "tabel_komponen": _tabel_komponen(grid, komponen_daftar, sesi_semua) if komponen_daftar else [], "bobot_komponen": bobot_komponen, "bobot_sub_rincian": bobot_sub_rincian, "tabel_poin": _tabel_poin(grid, bobot_sub_rincian) if bobot_sub_rincian else [], diff --git a/app/templates/form_nilai.html b/app/templates/form_nilai.html index c76f6b5..cb3a1bb 100644 --- a/app/templates/form_nilai.html +++ b/app/templates/form_nilai.html @@ -17,6 +17,13 @@ {% if pesan %}
{{ pesan }}
{% endif %} {% for w in peringatan %}
{{ w }}
{% endfor %} + {% if komponen_tanpa_sub %} +
RPS MK ini sudah punya bobot untuk {{ komponen_tanpa_sub|join(', ') }}, + tapi belum ada Sub-CPMK yang dicentang di bagian G — makanya komponen itu + {% if not komponen_daftar %}tidak muncul sama sekali{% else %}belum ikut muncul{% endif %} + di "Isi per Komponen" di bawah. Buka RPS → lalu centang Sub-CPMK-nya.
+ {% endif %} + {% if komponen_daftar %}

ISI PER KOMPONEN

diff --git a/app/templates/form_rps.html b/app/templates/form_rps.html index 82ab412..5c286eb 100644 --- a/app/templates/form_rps.html +++ b/app/templates/form_rps.html @@ -178,6 +178,12 @@ komponen yang tidak dipakai MK ini (opsional), tapi total seluruh komponen yang diisi harus tepat 100%. Centang Sub-CPMK yang dinilai tiap komponen; setiap Sub-CPMK harus tercakup minimal satu komponen agar CPMK/CPL-nya terukur.

+ {% if komponen_tanpa_sub %} +
Bobot sudah terisi tapi belum ada Sub-CPMK dicentang untuk: + {{ komponen_tanpa_sub|join(', ') }}. Komponen begini ikut dihitung ke total 100% di bawah, + tapi tidak akan muncul di halaman Input Nilai — centang minimal satu Sub-CPMK di + tiap baris sebelum menyimpan.
+ {% endif %}