1 / 34
Tekan ? untuk shortcut

Keyboard Shortcuts

→ / ↓ / SpaceSlide berikutnya
← / ↑Slide sebelumnya
1 – 9Langsung ke slide N
Home / EndSlide pertama / terakhir
?Toggle panel ini
EscTutup panel
LaravelSQL ServerPHPv2.1.7

Modul
Report

Dokumentasi teknis untuk developer — arsitektur, pola query, alur request, dan daftar endpoint modul pelaporan Medicare.

10
Sub-Modul
24
Controller
60+
Endpoint
3
Format Output
Scroll atau tekan untuk mulai
📋
01 · Gambaran Umum

Modul Report menyajikan data dari seluruh unit RS dalam laporan yang bisa dilihat di browser, dicetak PDF, atau diunduh Excel.

Rekam MedisKasirFinanceLabMutuPPITBDOTS

Dua Pendekatan Pelaporan

📄
Report — Statis

Query hard-coded di PHP controller. Cocok untuk laporan dengan format tetap dan logika bisnis kompleks.

21
Controller aktif
10
Sub-modul
60+
Endpoint
ReportBuilder — Dinamis

Laporan dikonfigurasi via UI editor, disimpan di database, dan dieksekusi secara runtime. Bisa dibuat tanpa deploy code baru.

3
Controller
6
Tabel DB
21
02 · Report Statis

21 controller aktif. Query hard-coded. Format laporan tetap dan tidak berubah-ubah.

Setiap sub-modul RS punya controller sendiri. Logika bisnis sepenuhnya dikontrol developer.

Report Statis — Controller per Unit RS

📊 Admission
RawatJalanController — kunjungan rawat jalan
💰 Finance
3 controller — umum, BPJS, per tagihan (95% kode identik)
🏦 Kasir
LaporanKasirController + OutStandingUMController
🧪 Lab
WaktuTungguController — hitung DATEDIFF dari order ke hasil
🦠 PPI
ReportPPIController — DataTables server-side
📁 Rekam Medis
6 controller — pasien masuk/keluar/inap, sensus, retensi, pergerakan IPD
✅ Mutu
LaporanFormController + StockObatController (DB replika)
💊 TBDOTS
2 controller — obat TB & masker per periode
📈 Laporan Umum
GraphicController + PhoneBookController (DataTables)
⚠️Tidak ada input validation, try-catch, atau pagination di semua controller statis.
03 · ReportBuilder

Laporan baru tanpa menulis atau deploy code baru.

Konfigurasi via UI editor · Disimpan di database · Dieksekusi secara runtime · Role-based access

ReportBuilder — Cara Kerja

Tabel Database

TabelFungsi
_LIRA_RB_REPORTMaster laporan
_LIRA_RB_KOMPONENKomponen (tabel/chart/teks)
_LIRA_RB_PANELPanel/section laporan
_LIRA_RB_KOMPONENHEADERKolom header
_LIRA_RB_REPORTAKSESHak akses per role
Format laporan sering berubah → pakai ReportBuilder
Dikelola non-developer → pakai ReportBuilder
⚠️Logika bisnis kompleks → pakai controller manual

Alur Eksekusi Runtime

Request masuk
ReportBuilderController
_getReportPanel()
Load panel dari _LIRA_RB_PANEL
_getPanelCard()
Load komponen dari _LIRA_RB_KOMPONEN
_getReportData()
SP: EXEC sp_report_xxx · Tabel: SELECT * FROM xxx
Response JSON
Render browser + export + role-based access
03a · Report Editor

Design Time. Membuat laporan via drag-drop editor tanpa sentuh code.

ReportEditorController · CRUD laporan, editor visual, import/export JSON, manajemen komponen

Report Editor — Design Time

Workflow Status Laporan

APPROVEStatusKeterangan
2PendingBaru dibuat, menunggu review
1AktifSudah di-approve, dapat diakses user
0Non-AktifDinonaktifkan
3RejectedDitolak
🔑Role Editing: Hanya user dengan role di syspar role_edit_rb_all yang bisa edit laporan yang sudah Aktif. User lain hanya View-Only.

Datasource Komponen — Dua Jenis

SP (Stored Procedure)
Prefix wajib: sp_report_
Eksekusi: EXEC sp_report_xxx @LIMIT=1000, @param=val
Tabel / View / Fungsi
Selain prefix di atas — contoh: vw_laporan_kasir
Eksekusi: SELECT TOP 1000 cols FROM datasource() WHERE filter

Fitur Utama Editor

FiturMethodFungsi
Listdata()DataTables — semua laporan + status
CreatesimpanReport()Nama, label, tipe laporan
UpdateupdateReport()Edit metadata laporan
Quick Reportquick_report()Generate dari template unit RS (GRPUNIT)
Editor drag-dropeditor()Panel, card, komponen visual
View-onlyview()Read-only untuk laporan Aktif
KomponenviewKomponen() · simpanKomponen()CRUD datasource, filter, kolom
Export JSONexportReport()Backup / transfer definisi
Import JSONimportReport()Restore + cek duplikasi

Report Akses & Report Tipe ReportEditorExtController

🔐 Report Akses — Hak Akses per Role

Cara Kerja
1. Admin pilih role dari dropdown (_lira_modulrole)
2. UI tampilkan dua panel:
   • Kiri: laporan belum bisa diakses role ini
   • Kanan: laporan sudah bisa diakses
3. Geser laporan antar panel (drag / klik)
4. Simpan → simpanReportAkses()
Mekanisme Simpan
DELETE _LIRA_RB_REPORTAKSES
  WHERE IDROLE = ?
INSERT ulang semua yang dipilih
Per-role replace — bukan diff. Sederhana tapi rentan race condition kalau dua admin bersamaan.
⚠️Hanya laporan dengan AN=1 (aktif) dan APPROVE=1 (sudah approve) yang muncul di UI Report Akses.

🏷️ Report Tipe — Kategori Laporan

CRUD Tipe Laporan
Mengelola kategori/tipe laporan untuk pengelompokan di UI ReportBuilder. Tiap tipe punya nama + sub-modul Medicare.
MethodFungsi
reporttipe()List semua tipe — DataTables (Tipe, Modul, Action)
simpanReportTipe()Tambah tipe baru
updateReportTipe()Edit nama/modul tipe
removeReportTipe()Hard delete
Sumber Sub-Modul
Setiap tipe dikaitkan ke sub-modul via IDMODUL dari tabel _LIRA_MODUL. Daftar sub-modul yang muncul diambil dari syspar idmodulreport (ID parent modul Report).
03b · Run Time

Run Time. Render chain 7 method bersarang dari request sampai data sampai di browser.

ReportBuilderController · server-side DataTable, export Excel/PDF, cross-database query

Run Time — Render Chain & Fitur

Render Chain Lengkap

render()
Ambil daftar laporan via JOIN REPORTAKSES + MODULROLEUSER
getreportdetail() → _generatereport()
Jika SHOWTOC=1 → render TOC sidebar fixed
_getReportPanel()
Loop per panel
_getPanelCard()
Loop per card di panel
_getCardKomponen() → _getTipe()
Loop per komponen, dispatch by TIPE
_getReportData() — jika TIPE='TABLE'
Cek LINKEDSERVER/DBSOURCE · SP atau Tabel · Eksekusi query

Fitur DataTable Run Time

FiturDetail
Server-sideAJAX ke dataTable() — filter, sort, paginasi di server
Format numerikISNUMERIC=1 → auto-format via accounting.js
Kolom warnaBACKGROUNDCOLOR per kolom — inject CSS class dinamis
Total footerISSUM=1 — hitung total kolom di footer
Export ExceltoExcel() — Spout XLSX + kop RS
Export PDFtoPDF() — snappy/wkhtmltopdf, A4 atau A5
Sembunyikan exportSyspar is_hide_export_report_modul

Tipe Filter Komponen

TipeRender
TEXT<input type="text"> — input bebas
COMBOBOX<select> + Select2 · sumber: DATASOURCE atau VALUESDATA (semicolon-sep)
DATEjQuery datepicker — tanggal tunggal
DEFAULTFILTERDateRangePicker — field dari komponen, batas dari MAXRANGE

Fitur Lanjutan

LINKEDSERVER + DBSOURCE — query ke server/DB lain via _LIRA_RB_SERVER
GROUPSUMMARY — group field1|field2, hasilkan baris unik + SUMGROUP
SHOWTOC — TOC sidebar dengan anchor #panel_{ID}
SP @LIMIT — auto-inject @LIMIT=1000 ke semua SP
📁
04 · Struktur Folder

Semua report ada di satu folder, terstruktur per unit RS.

app/Http/Controllers/Modul/Report/

Struktur Folder & File

Report/
├── Admission/
│ └── RawatJalanController.php
├── Finance/
│ ├── LaporanKeuanganController.php
│ ├── LaporanKeuanganBPJSController.php
│ └── LaporanKeuanganTagihanController.php
├── Kasir/
│ ├── LaporanKasirController.php
│ └── OutStandingUMController.php
├── Lab/
│ └── WaktuTungguController.php
├── Laporan/
│ ├── GraphicController.php
│ └── PhoneBookController.php
├── Mutu/ ...
├── PPI/ ...
├── Rekammedis/ 6 file
└── Tbdots/ ...
ReportBuilder/
├── ReportBuilderController.php
Runtime: eksekusi laporan
├── ReportEditorController.php
Design: buat & konfigurasi
└── ReportEditorExtController.php
Ekstensi: role akses & tipe

Rekammedis/ (detail)
├── PasienInapController.php
├── PasienMasukController.php
├── PasienKeluarController.php
├── PergerakanPasienIPDController.php
├── RetensiController.php
└── SensusRanapController.php
10
05 · Sub-Modul

10 sub-modul. 24 controller. Mencakup seluruh unit operasional RS.

Admission · Finance · Kasir · Lab · Rekam Medis · Mutu · PPI · TBDOTS · Laporan · ReportBuilder

10 Sub-Modul

📊 Admission
Kunjungan rawat jalan — filter tanggal, dokter, poli
RawatJalanController
💰 Finance
Rekap pendapatan & jasa medis — umum, BPJS, per tagihan
3 Controller
🏦 Kasir
Pendapatan, rekap, rekon ERP, batal billing, outstanding UM
2 Controller
🧪 Lab
Waktu tunggu pemeriksaan via DATEDIFF SQL Server
WaktuTungguController
📁 Rekam Medis
Pasien masuk/keluar/inap, sensus ranap, retensi, pergerakan IPD
6 Controller
✅ Mutu
Form mutu quality control & stok obat dari DB replika
2 Controller
🦠 PPI
Pencegahan & Pengendalian Infeksi — DataTables server-side
ReportPPIController
💊 TBDOTS
Program TB — obat TB & masker per periode dan bagian
2 Controller
📈 Laporan Umum
Grafik kunjungan pasien & buku telepon internal RS
Graphic · PhoneBook
✨ ReportBuilder
Laporan dinamis tanpa deploy — konfigurasi via UI editor, disimpan di database
3 Controller
🔄
06 · Pola Controller

Semua controller ikut tiga langkah yang sama: form, preview, download.

Satu template konsisten di 21 controller. Pelajari satu, paham semua.

Template Controller

class NamaController extends Controller
{
    private $idmodul;

    public function __construct(Request $request)
    {
        $this->idmodul = $request->input('idmodul');
    }

    // Step 1 — Form filter
    public function index(Request $request)
    {
        $data['idmodul'] = $this->idmodul;
        $data['bagian']  = Bagian::select()->get();
        $data['dokter']  = Dokter::select()->get();
        return view('modul.report.xxx.index', $data);
    }

    // Step 2 — Preview hasil
    public function laporan_xxx(Request $request)
    {
        $data['data'] = self::query_data($request);
        return view('modul.report.xxx.preview_laporan', $data);
    }

    // Step 3 — Export Excel
    public function download_excel(Request $request)
    {
        $data['data'] = self::query_data($request);
        return view('modul.report.xxx.preview_laporan_excel', $data);
    }
}

Tiga Blade View yang Dibutuhkan

index.blade.php — form filter
preview_laporan.blade.php — hasil
preview_laporan_excel.blade.php — download

Base Class

App\Http\Controllers\Controller
Semua Report controller extends Laravel base. Tidak ada custom base class, trait, atau shared helper khusus untuk Report.
⚠️Tidak ada input validation, tidak ada try-catch, dan tidak ada pagination di semua controller statis.
80%
07 · Query Database

80% dari semua query menggunakan raw SQL via DB::select()

Eloquent hanya dipakai untuk dropdown master data. Query Builder hampir tidak ada.

Query Database

Distribusi Metode

Raw SQL
0%
Eloquent
0%
Query Builder
0%

Dua Database Connection

sqlsrv
DB produksi utama — transaksi real-time
report
DB replika — laporan berat agar tidak bebani DB utama

Pola Paling Umum

// Build WHERE dari form filter
$where = " 1=1 ";
if ($request->tgl_dari) {
    $where .= " AND TGLBAYAR >= '"
              .$request->tgl_dari."'";
}
if ($request->bagian) {
    $where .= " AND KDBAGIAN = '"
              .$request->bagian."'";
}
$result = DB::select("
    SELECT P.NMPASIEN, B.TGLBAYAR
    FROM BAYAR B
    INNER JOIN PASIEN P ON ...
    WHERE $where
");
🔴SQL Injection Risk$request langsung di-concatenate di 15+ tempat. Gunakan parameter binding saat tambah kode baru.
07b · Complex Querying

Multi-table JOIN, WITH (NOLOCK), dan 5 format export berbeda.

Pola yang dipakai di Finance, Kasir, dan Rekam Medis — kombinasi CASE WHEN, ISNULL, dan DATEDIFF untuk laporan kompleks.

Complex Querying & Exporting

Multi-Table JOIN (Finance / Kasir)

$result = DB::select("
  SELECT
    R.NOREG,
    P.NMPASIEN,
    ISNULL(B.JMLBAYAR, 0)    AS JMLBAYAR,
    ISNULL(I.NOMINVOICE, 0)  AS NOMINVOICE,
    CASE WHEN B.NOINVOICE IS NULL
         THEN 'Belum Bayar'
         ELSE 'Lunas' END     AS STATUS
  FROM REGDR R
  INNER JOIN PASIEN  P ON R.NOPASIEN  = P.NOPASIEN
  LEFT  JOIN INVOICE I ON R.NOREG     = I.NOREG
  LEFT  JOIN BAYAR   B ON I.NOINVOICE = B.NOINVOICE
  WHERE $where
  ORDER BY R.NOREG DESC
");
ℹ️Pola umum 3–5 tabel dengan kondisi dinamis dari filter form: REGDR → PASIEN → INVOICE → BAYAR. CASE WHEN untuk status, ISNULL untuk nilai default.

Teknik Performa SQL Server

TeknikKapan Dipakai
WITH (NOLOCK)Laporan read-only — hindari blocking dari transaksi billing aktif
SELECT TOP nBatasi baris hasil — pengganti LIMIT MySQL
LTRIM(RTRIM(col))Strip spasi data lama — TRIM() tidak ada di SQL Server 2014 ke bawah
DATEDIFF(minute,…)Selisih waktu — Lab: order → hasil
Koneksi reportQuery berat → DB replika, jangan bebani DB produksi

5 Format Export — Cross-Reference

FormatImplementasi
HTML Bladereturn view(...) — semua controller
Excel via BladeBlade + header Content-Disposition: attachment
Excel SpoutBox\Spout\Writer\WriterFactory — Finance
PDFbarryvdh/laravel-dompdf — LaporanKasir
JSON DataTablesYajra\DataTables — PhoneBook, PPI, RB
08 · Flow Request-Response

Tiga langkah yang selalu berulang di setiap laporan.

GET form  →  POST query  →  GET download

Flow Request → Response

1
GET /report/xxxindex() — load dropdown Bagian, Dokter, Penjamin, lalu return form HTML ke browser
2
POST /report/xxx/laporanlaporan_xxx() — build WHERE dari filter, DB::select(), return view preview dengan tabel hasil
3
GET /report/xxx/download_exceldownload_excel() — query ulang, return Blade Excel + header Content-Disposition: attachment

Pola Khusus

DataTables — PPI · PhoneBook
Index tampilkan tabel kosong. Data diisi via AJAX GET ke anyData yang return JSON format Yajra DataTables.
Sensus Ranap
Satu form → 6 endpoint GET terpisah: pasien_awal, pasien_masuk, pasien_pulang, pasien_pindah, pasien_pindahan, pasien_sisa
Finance BPJS
Method detail_rekap_jasa() mencapai 1.276 baris — if-else berlapis untuk berbagai kombinasi filter.
5
09 · Format Output

Lima format output untuk lima kebutuhan berbeda.

HTML Blade · Excel View · Excel Spout · PDF · JSON DataTable

Format Output

🌐 HTML Blade
Semua controller — form filter & preview di browser
return view('modul.report.xxx', $data)
📄 Excel — View Based
Rekam Medis, Kasir, Lab, TBDOTS — Blade view + header download. Browser buka di Excel.
Content-Disposition: attachment
📊 Excel — Spout
Finance — Box\Spout\Writer\WriterFactory untuk xlsx terstruktur dengan formatting.
WriterFactory::create(Type::XLSX)
🖨️ PDF
Hanya LaporanKasirController — barryvdh/laravel-dompdf
PDF::loadView(...)->stream()
⚡ JSON / DataTable
PhoneBook, PPI, ReportBuilder — Yajra\DataTables server-side & response()->json()
ℹ️Excel "view-based" mengembalikan HTML dengan header application/vnd.ms-excel — bukan xlsx asli, tapi browser membukanya di Excel.
60+
10 · Endpoint List

Lebih dari 60 endpoint tersebar di 10 sub-modul.

Semuanya terdaftar di routes/web.php dalam group prefix /report

📁 Rekam Medis 20 endpoint

🏦 Kasir 14 endpoint

💰 Finance 8 endpoint

🔬 Lab · PPI · Mutu · TB 23 endpoint

⚠️
11 · Catatan Developer

Hal-hal yang wajib diketahui sebelum menyentuh kode ini.

SQL Server bukan MySQL · Throwable bukan Exception · Parameter binding bukan concatenation

Catatan Penting untuk Developer

SQL Server — Bukan MySQL

SQL Server ✓MySQL ✗
SELECT TOP 10 *LIMIT 10
LTRIM(RTRIM(col))TRIM(col)
ISNULL(col, '')IFNULL(col, '')
CONVERT(varchar,t,120)DATE_FORMAT()
DATEDIFF(minute,t1,t2)TIMESTAMPDIFF()
🔴
Exception Handling
Pakai catch (\Throwable $e) bukan catch (\Exception $e) — tidak menangkap TypeError dan Error.
Response AJAX: hasil: 1 sukses · hasil: 0 gagal · hasil: 25 duplikat

SQL Injection — Gunakan Parameter Binding

// JANGAN — rentan SQL injection
$where .= " AND KDBAGIAN = '".$request->bagian."'";
$result = DB::select("SELECT ... WHERE $where");

// GUNAKAN — aman dengan parameter binding
$params = [];
$where  = " 1=1 ";
if ($request->bagian) {
    $where   .= " AND KDBAGIAN = ?";
    $params[] = $request->bagian;
}
$result = DB::select(
    "SELECT ... FROM ... WHERE $where",
    $params
);
Koneksi DB Replika report
Pastikan ada di config/database.php di environment baru. Dipakai oleh StockObatController dan LaporanFormController. Tanpa ini, laporan stok & mutu akan error.
🎯

Terima Kasih

Dokumentasi lengkap tersedia di REPORT_MODULE_DOCS.md

10 Sub-Modul24 Controller60+ Endpoint80% Raw SQLReportBuilder
Hal yang Perlu Diingat
🔴 Gunakan catch (\Throwable $e) untuk exception
🔐 Gunakan parameter binding DB::select($q, $params)
🗄️ Pastikan koneksi report ada di database.php
🛢️ SQL Server: TOP n bukan LIMIT n
Medicare Docs