diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b4aaba..bfd652f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,6 +77,8 @@ _None yet._ - **Graduation wizard `finish()` fatal TypeError on submit:** `Graduation::finish()` was declared `: string` but returns a `RedirectResponse` (`redirect()->to('graduation/guidance')`), throwing `TypeError: Return value must be of type string` the moment the wizard is actually submitted to Neo Feeder. Changed the return type to `CodeIgniter\HTTP\RedirectResponse`. Also, the full submission iterates the whole batch with a synchronous call chain per student (InsertMahasiswaLulusDO + academic edits + thesis grade), which could exceed PHP's default 60 s limit on large batches → added `set_time_limit(0)` at the top of `finish()` — #113 +- **Graduation wizard academic edits silently rejected by Neo Feeder (#117):** `Graduation::finish()` pushed per-semester academic corrections (status / IPK / IPS) as a *partial* `UpdatePerkuliahanMahasiswa` record (only `id_status_mahasiswa`, `ips`, `ipk`). Neo Feeder rejects partial records — it enforces `id_status_mahasiswa`, `biaya_kuliah_smt` and `id_pembiayaan` even though the GetDictionary schema lists only `id_status_mahasiswa` as NOT NULL — so every academic edit failed and the last-semester IPK/status was never actually updated. The failure was also invisible because the response was discarded (no result row). `finish()` now sends the **full** activity row (minus the composite key) plus `id_pembiayaan` resolved via `GetListRiwayatPendidikanMahasiswa`, with only the edited fields overridden — the same record shape as the Verifikasi IPK menu — and records a per-semester success/failure result so the guidance page shows what actually happened — #117 + - **Graduation wizard transcript completeness (BUG-001, #89):** the "Kelengkapan Transkrip" check is now sourced from the Neo Feeder "Cek Transkrip Mahasiswa" menu data (cloud REST `/ws/transkrip/nilai_mahasiswa`, using BASE's existing WS `act` token as Bearer — no separate cloud login) instead of `GetTranskripMahasiswa`. Completeness now requires the thesis/skripsi course to exist with a non-empty grade; the per-course `choosed` transcript-inclusion marker is shown as status detail (badge "Nilai ada · masuk transkrip"/"belum masuk transkrip"/"Tanpa nilai") but no longer gates the result. New `NeoFeeder::getCekTranskripMahasiswa()` + `cloudGet()` helper; card 2b renders the detected thesis course (MK, kode, semester, nilai, status). - **FA6 icon consistency:** `header.php` logout button and `DESIGN.md` reference still used FA5 deprecated names (`fa-sign-out-alt` → `fa-right-from-bracket`, `fa-tachometer-alt` → `fa-gauge-high`) — aligned to canonical FA6 names to match `sidebar.php` - **Sidebar active state:** fixed route detection — `getPath()` returned `index.php/dashboard` instead of `dashboard`; now uses `current_url()` with `basename()` which handles both URL formats diff --git a/app/Controllers/Graduation.php b/app/Controllers/Graduation.php index 99533c9..ea042e5 100644 --- a/app/Controllers/Graduation.php +++ b/app/Controllers/Graduation.php @@ -736,6 +736,10 @@ public function finish(): RedirectResponse } // Push per-semester academic corrections (status/ipk/ips) to Neo Feeder. + // Neo Feeder rejects partial UpdatePerkuliahanMahasiswa records + // (id_status_mahasiswa, biaya_kuliah_smt, id_pembiayaan are all + // enforced live), so we send the full row + id_pembiayaan with the + // edited fields overridden — same record shape as Verifikasi IPK. $edits = $student['academics'] ?? []; if (count($edits) > 0) { $nimSafe = trim((string) ($student['nim'] ?? $g['nim'])); @@ -744,27 +748,45 @@ public function finish(): RedirectResponse 'limit' => 50, ]); if (($acResp['error_code'] ?? -1) === 0 && isset($acResp['data'])) { - $regByIdSemester = []; + $rowByIdSemester = []; foreach ($acResp['data'] as $r) { - $regByIdSemester[$r['id_semester']] = $r['id_registrasi_mahasiswa']; + $rowByIdSemester[$r['id_semester']] = $r; } + + // id_pembiayaan is not present on activity rows; resolve it once + // per student from the riwayat record (same as Verifikasi IPK). + $pembiayaan = ''; + $rivResp = $this->neoFeeder->getListRiwayatPendidikanMahasiswa($apiToken, [ + 'filter' => "nim='{$nimSafe}'", + 'limit' => 1, + ]); + if (($rivResp['error_code'] ?? -1) === 0 && isset($rivResp['data'][0]['id_pembiayaan'])) { + $pembiayaan = (string) $rivResp['data'][0]['id_pembiayaan']; + } + foreach ($edits as $idSemester => $edit) { - if (! isset($regByIdSemester[$idSemester])) { + if (! isset($rowByIdSemester[$idSemester])) { continue; } - $akRecord = []; + $row = $rowByIdSemester[$idSemester]; + $record = $row; + unset($record['id_registrasi_mahasiswa'], $record['id_semester']); + $record['id_pembiayaan'] = $pembiayaan; foreach (['id_status_mahasiswa', 'ips', 'ipk'] as $field) { if (isset($edit[$field]) && (string) $edit[$field] !== '') { - $akRecord[$field] = $edit[$field]; + $record[$field] = $edit[$field]; } } - if (count($akRecord) > 0) { - $this->neoFeeder->updatePerkuliahanMahasiswa( - $apiToken, - (string) $regByIdSemester[$idSemester], - (string) $idSemester, - $akRecord - ); + $akResp = $this->neoFeeder->updatePerkuliahanMahasiswa( + $apiToken, + (string) $row['id_registrasi_mahasiswa'], + (string) $idSemester, + $record + ); + if (($akResp['error_code'] ?? -1) === 0) { + $results[] = ['nim' => $g['nim'], 'success' => true, 'msg' => "Akademik semester {$idSemester} terupdate."]; + } else { + $results[] = ['nim' => $g['nim'], 'success' => false, 'msg' => $akResp['error_msg'] ?? "Gagal update akademik semester {$idSemester}."]; } } }