5 Commits

Author SHA1 Message Date
Power BI Dev 374bdb5565 Perbaiki isi RPS unduhan yang nyasar ke baris salah (Peta CPL, Deskripsi, dst)
build_rps() mengisi blok naratif (Peta CPL-CPMK, Deskripsi Singkat MK,
Bahan Kajian, Pustaka, Media, Dosen Pengampu, MK Prasyarat) lewat
t.cell(18, 2) dst -- indeks baris tetap sesuai template asli (39 baris).
Tapi baris-baris itu dieksekusi SETELAH daftar CPL/CPMK/Sub-CPMK
digandakan & baris contohnya dibuang -- jumlah baris yang disisipkan
beda-beda tiap MK (tergantung berapa CPL/CPMK/Sub-CPMK-nya), jadi
t.cell(18, 2) di tabel yang sudah berubah itu tidak lagi menunjuk baris
"Peta CPL-CPMK" yang dimaksud. Teks jadi nyasar ke sel/baris lain,
termasuk kolom sempit -- terlihat sebagai puluhan halaman teks terpotong
huruf demi huruf.

Pola yang benar sudah dipakai untuk tabel mingguan (trs[31], trs[33],
dst -- referensi elemen XML baris asli yang dibekukan di awal, tak
ikut bergeser). Terapkan pola sama (helper cell()) untuk blok naratif
yang kelewat.

Diverifikasi: label & isi sekarang sejajar benar (baris "Peta CPL - CP
MK" berisi peta CPMK->CPL, bukan lagi nama dosen pengampu), dokumen
turun dari puluhan halaman rusak jadi 2 halaman rapi untuk bagian ini.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 21:42:01 +07:00
Power BI Dev de65ca99e6 Merge branch 'ubah/teks-peringatan-subcpmk-komponen' into main 2026-08-09 20:58:45 +07:00
Power BI Dev adf2918e85 Ubah teks peringatan Sub-CPMK-komponen: fokus ke "belum ditautkan"
Framing lama ("RPS sudah punya bobot untuk X, tapi belum ada Sub-CPMK
dicentang") terkesan seperti pengisian sengaja yang cuma kurang
langkah terakhir. Padahal akar masalahnya sering kali bobot bawaan
aplikasi (KOMPONEN_DEFAULT) yang belum pernah disentuh dosen sama
sekali — reframing ke "Sub-CPMK belum ditautkan ke komponen penilaian"
lebih jujur ke kondisi sebenarnya.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 20:56:18 +07:00
Power BI Dev 3c9482ee23 Merge branch 'fitur/peringatan-komponen-tanpa-subcpmk' into main 2026-08-09 20:33:38 +07:00
Power BI Dev e5d45cdcdd 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 <noreply@anthropic.com>
2026-08-09 20:29:15 +07:00
4 changed files with 47 additions and 8 deletions
+15 -8
View File
@@ -130,6 +130,13 @@ def build_rps(d: dict) -> bytes:
trs = [r._tr for r in t.rows] # indeks baris template asli
def cell(idx, col):
"""Ambil sel dari baris ASLI template lewat trs[idx] (referensi XML
beku), bukan t.cell(idx, col) yang ikut bergeser tiap kali baris
CPL/CPMK/Sub-CPMK digandakan/dibuang di atasnya — pakai t.cell()
langsung untuk baris di bawah blok itu akan salah sasaran."""
return _Row(trs[idx], t).cells[col]
def isi_daftar(proto_idx, hapus_idx, items, kolom_kode=2, kolom_isi=5):
"""Isi blok daftar (CPL/CPMK/Sub-CPMK): prototipe digandakan per item."""
proto = trs[proto_idx]
@@ -153,17 +160,17 @@ def build_rps(d: dict) -> bytes:
f"{c['kode']}{', '.join(c.get('cpl', [])) or '-'}"
for c in d.get("cpmk", [])
)
_set_text(t.cell(18, 2), peta_txt)
_set_text(t.cell(19, 2), d.get("deskripsi", ""))
_set_text(t.cell(20, 2), d.get("bahan_kajian", ""))
_set_text(cell(18, 2), peta_txt)
_set_text(cell(19, 2), d.get("deskripsi", ""))
_set_text(cell(20, 2), d.get("bahan_kajian", ""))
utama = d.get("referensi", [])
pendukung = d.get("referensi_pendukung", [])
_set_text(t.cell(22, 2), "\n".join(f"{i}. {r}" for i, r in enumerate(utama, 1)))
_set_text(t.cell(24, 2), "\n".join(f"{i}. {r}" for i, r in enumerate(pendukung, 1)))
_set_text(t.cell(25, 2), d.get("media", ""))
_set_text(t.cell(26, 2), ident.get("pengampu", ""))
_set_text(t.cell(27, 2), ident.get("prasyarat") or "")
_set_text(cell(22, 2), "\n".join(f"{i}. {r}" for i, r in enumerate(utama, 1)))
_set_text(cell(24, 2), "\n".join(f"{i}. {r}" for i, r in enumerate(pendukung, 1)))
_set_text(cell(25, 2), d.get("media", ""))
_set_text(cell(26, 2), ident.get("pengampu", ""))
_set_text(cell(27, 2), ident.get("prasyarat") or "")
# ── tabel mingguan ──
proto_norm, proto_uts, proto_uas = trs[31], trs[33], trs[37]
+19
View File
@@ -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 [],
+7
View File
@@ -17,6 +17,13 @@
{% if pesan %}<div class="info">{{ pesan }}</div>{% endif %}
{% for w in peringatan %}<div class="peringatan">{{ w }}</div>{% endfor %}
{% if komponen_tanpa_sub %}
<div class="peringatan"><b>Sub-CPMK belum ditautkan ke komponen penilaian</b> untuk
{{ komponen_tanpa_sub|join(', ') }} — segera isi di RPS bagian G. Selama belum ditautkan,
komponen itu {% if not komponen_daftar %}tidak muncul sama sekali{% else %}belum ikut muncul{% endif %}
di "Isi per Komponen" di bawah. <a href="/rps/{{ peta.kode }}">Buka RPS &rarr;</a> lalu centang Sub-CPMK-nya.</div>
{% endif %}
{% if komponen_daftar %}
<h2 class="bagian">ISI PER KOMPONEN</h2>
<table class="grid" style="max-width:760px">
+6
View File
@@ -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.</p>
{% if komponen_tanpa_sub %}
<div class="peringatan"><b>Sub-CPMK belum ditautkan ke komponen penilaian</b> — segera centang
minimal satu Sub-CPMK untuk: {{ komponen_tanpa_sub|join(', ') }}. Tanpa tautan ini, komponen
tersebut <b>tidak akan muncul</b> di halaman Input Nilai meski bobotnya sudah dihitung ke
total 100% di bawah.</div>
{% endif %}
<div class="gulir">
<table class="grid">
<thead>