> ## Documentation Index
> Fetch the complete documentation index at: https://docs.quinnsambal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Reports

<style>
  {`
    [class*="max-w-none"][class*="table"] {
      display: block !important;
      overflow-x: auto !important;
      max-width: 100% !important;
      width: 100% !important;
      flex-grow: 0 !important;
    }
    [class*="max-w-none"][class*="table"] > table {
      width: 100% !important;
      max-width: 100% !important;
      table-layout: fixed !important;
    }
    .mermaid {
      max-width: 100% !important;
      overflow-x: auto !important;
    }
    article svg[role="img"] {
      max-width: 100% !important;
      height: auto !important;
    }
    article img, .prose img {
      max-width: 100% !important;
      height: auto !important;
    }
    img[src*="LOGO"], img[src*="logo"] {
      max-width: 120px !important;
      max-height: 40px !important;
      width: auto !important;
      height: auto !important;
      object-fit: contain !important;
    }
    `}
</style>

***

title: "Financial Reports"
description: "Empat laporan keuangan inti (Laba Rugi, Neraca, Neraca Saldo, Anggaran vs Aktual) dengan mesin dual-source, audit completeness, dan fitur cetak di SNISHOP ERP."
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

# Financial Reports

<img src="https://mintcdn.com/quinnofspicy/e4f_upKhVWcjsUmM/docs/mintlify/screenshots/finance/financial-reports.png?fit=max&auto=format&n=e4f_upKhVWcjsUmM&q=85&s=707350783fd087d7b29b741258c874f4" alt="Financial Reports" width="1920" height="1080" data-path="docs/mintlify/screenshots/finance/financial-reports.png" />

Halaman Financial Reports adalah pusat pelaporan keuangan SNISHOP ERP. Empat laporan inti dihasilkan secara otomatis dari data transaksi yang sudah tercatat, dengan mesin dual-source yang memprioritaskan Jurnal GL dan fallback ke Buku Kas jika data GL belum lengkap.

## Arsitektur Pelaporan

```mermaid theme={null}
graph TB
    subgraph SUMBER_DATA["Sumber Data"]
        GL[GL Journal Entry<br/>status: posted]
        FR[Financial Record<br/>8 sumber]
        BD[Budget<br/>4 periode]
        ACC[GL Account<br/>COA 3 level]
    end

    subgraph MESIN["Dual-Source Reporting Engine"]
        PREF{GL Revenue<br/>Exist?}
        PRIMARY[Primary: Jurnal GL]
        FALLBACK[Fallback: Buku Kas]
        COMPLETE[evaluateCompleteness<br/>Audited vs Provisional]
    end

    subgraph LAPORAN["4 Laporan Inti"]
        PL[Profit & Loss<br/>Laba Rugi]
        BS[Balance Sheet<br/>Neraca]
        TB[Trial Balance<br/>Neraca Saldo]
        BA[Budget vs Actual<br/>Anggaran vs Aktual]
    end

    GL --> PREF
    FR --> PREF
    PREF -->|Ya| PRIMARY
    PREF -->|Tidak| FALLBACK
    PRIMARY --> COMPLETE
    FALLBACK --> COMPLETE
    COMPLETE --> PL
    ACC --> BS
    GL --> BS
    ACC --> TB
    GL --> TB
    BD --> BA
    FR --> BA
```

## Akses Halaman

URL: `/finance` → tab **Laporan**

Empat tab laporan tersedia dalam grid layout (2 kolom di mobile, 4 kolom di desktop):

| Tab | Label | Komponen | Fungsi |
| - | - | - | - |
| `profit_loss` | Laba Rugi | `ProfitLossReport` | Pendapatan, HPP, laba kotor, beban operasional, laba bersih |
| `balance_sheet` | Neraca | `BalanceSheetReport` | Aset, liabilitas, ekuitas dengan validasi persamaan akuntansi |
| `trial_balance` | Neraca Saldo | `TrialBalanceReport` | Semua akun GL dengan total debit/kredit dan status keseimbangan |
| `budget_vs_actual` | Anggaran vs Aktual | `BudgetVsActualReport` | Perbandingan anggaran vs realisasi dengan variansi dan chart |

## KPI Summary

Empat kartu ringkasan ditampilkan di bagian atas, dihitung secara real-time via `useMemo`:

| KPI | Sumber | Perhitungan |
| - | - | - |
| **Total Pendapatan** | FinancialRecord | `SUM(amount)` dimana `type === 'income'` |
| **Total Pengeluaran** | FinancialRecord | `SUM(amount)` dimana `type === 'expense'` |
| **Laba Bersih** | Computed | `totalIncome - totalExpense` |
| **Jurnal Posting** | GLJournalEntry | `COUNT(*)` dimana `status === 'posted'` |

## Seleksi Periode

Lima preset periode plus opsi kustom:

| Periode | Label | Rentang Tanggal |
| - | - | - |
| `this_month` | Bulan Ini | Tanggal 1 hari ini → hari ini |
| `last_month` | Bulan Lalu | Tanggal 1 bulan lalu → akhir bulan lalu |
| `last_3_months` | 3 Bulan | 3 bulan terakhir → hari ini |
| `this_year` | Tahun Ini | 1 Januari tahun ini → hari ini |
| `custom` | Kustom | User memilih tanggal mulai dan selesai |

Mode custom menampilkan dua field `<input type="date">` (start/end) dengan tombol "Apply" untuk menerapkan filter.

## Data Loading

Empat entity di-fetch secara paralel via `cachedRequest`:

```
GLAccount       → filter: company_id
GLJournalEntry  → filter: company_id, status: "posted"
Budget          → filter: company_id
FinancialRecord → filter: company_id
```

Cache layer (`cachedRequest` dari `requestManager`) memastikan data yang sama tidak di-fetch berulang dalam satu sesi. Tombol **Refresh** memanggil `loadData()` untuk memuat ulang seluruh data.

***

## Laporan Laba Rugi (Profit & Loss)

### Mesin Dual-Source

Laporan Laba Rugi menggunakan strategi dual-source untuk memastikan akurasi data:

```mermaid theme={null}
flowchart LR
    A[GL Journal Entry<br/>posted] --> B{GL Revenue<br/>Exist?}
    C[Financial Record] --> B
    B -->|Ya| D[MODE: Jurnal GL]
    B -->|Tidak| E[MODE: Buku Kas]
    D --> F[Laporan Laba Rugi]
    E --> F
```

**Prioritas sumber data:**

| Prioritas | Sumber | Kapan Digunakan | Badge |
| - | - | - | - |
| 1 (Primary) | GL Journal Entry | Jika ada journal entry dengan akun revenue | "Jurnal GL" |
| 2 (Fallback) | Financial Record | Jika belum ada data GL yang cukup | "Buku Kas" |

### Audit Completeness

Sistem menilai kualitas data menggunakan `evaluateCompleteness()` dari `financeLogic`:

| Status | Ikon | Arti |
| - | - | - |
| **Audited** | `ShieldCheck` | Data lengkap dari jurnal GL yang sudah diposting |
| **Provisional** | `AlertCircle` | Data berdasarkan buku kas, belum diaudit penuh |

Banner status ditampilkan di bagian atas laporan untuk transparansi.

### Struktur Laporan

```
PENDAPATAN
├── Total Revenue (dari semua sumber income)
├── (-) Channel Fees / Marketplace MDR
└── = Net Settlement

HPP (Harga Pokok Penjualan)
├── Total HPP (kategori HPP)
└── = Gross Profit (Laba Kotor)

BEBAN OPERASIONAL
├── Beban Gaji
├── Beban Bahan Baku
├── Beban Operasional
├── Beban Produksi
├── Beban Perjalanan
├── Beban Makan
├── Beban Akomodasi
├── Beban Peralatan
├── Beban Perlengkapan Kantor
├── Beban Pelatihan
└── Beban Lainnya

= LABA BERSIH (Net Profit/Loss)
```

### Utilitas yang Digunakan

| Fungsi | Sumber | Peran |
| - | - | - |
| `isRevenueRecord()` | `financeLogic` | Identifikasi record pendapatan |
| `isCashInflowRecord()` | `financeLogic` | Identifikasi arus kas masuk |
| `isExpenseRecord()` | `financeLogic` | Identifikasi record beban |
| `isHppCategory()` | `financeHelper` | Identifikasi kategori HPP |
| `evaluateCompleteness()` | `financeLogic` | Menilai kelengkapan data (audited/provisional) |

### Metrik yang Dilacak

| Metrik | Perhitungan |
| - | - |
| `totalRevenue` | SUM semua record pendapatan |
| `totalChannelFees` | SUM marketplace MDR / channel fees |
| `netSettlement` | `totalRevenue - totalChannelFees` |
| `totalExpense` | SUM semua record beban |
| `totalCashInflow` | SUM semua arus kas masuk |
| `grossProfit` | `netSettlement - totalHPP` |

***

## Laporan Neraca (Balance Sheet)

### Persamaan Akuntansi

Neraca disusun berdasarkan persamaan akuntansi fundamental:

```
ASET = LIABILITAS + EKUITAS
```

Sistem memvalidasi persamaan ini secara otomatis. Jika `totalAssets !== totalLiabilities + totalEquity` (toleransi \< Rp 1), banner peringatan ditampilkan.

### Struktur Neraca

```mermaid theme={null}
graph TD
    BS[Neraca / Balance Sheet]
    BS --> A[ASET]
    BS --> L[LIABILITAS]
    BS --> E[EKUITAS]

    A --> A1[Aset Lancar]
    A --> A2[Aset Tetap]
    A1 --> A1a[Kas & Bank]
    A1 --> A1b[Piutang Usaha]
    A1 --> A1c[Inventori]
    A1 --> A1d[Beban Dibayar Dimuka]
    A2 --> A2a[Peralatan]
    A2 --> A2b[Kendaraan]
    A2 --> A2c[(-) Akumulasi Penyusutan]

    L --> L1[Liabilitas Jangka Pendek]
    L --> L2[Liabilitas Jangka Panjang]
    L1 --> L1a[Hutang Usaha]
    L1 --> L1b[Pinjaman Jangka Pendek]
    L1 --> L1c[Beban Masih Harus Dibayar]
    L2 --> L2a[Pinjaman Jangka Panjang]
    L2 --> L2b[Pajak Tangguhan]

    E --> E1[Modal Saham]
    E --> E2[Laba Ditahan]
    E --> E3[Laba Tahun Berjalan]
```

### Perhitungan dari GL

Neraca dihitung dari saldo GL Account dan journal entries yang sudah diposting:

| Bagian | Sumber GL | Perhitungan |
| - | - | - |
| Aset | Akun bertipe `asset` | SUM(debit) - SUM(credit) |
| Liabilitas | Akun bertipe `liability` | SUM(credit) - SUM(debit) |
| Ekuitas | Akun bertipe `equity` | SUM(credit) - SUM(debit) |

***

## Laporan Neraca Saldo (Trial Balance)

### Fungsi

Neraca Saldo列出 seluruh akun GL dengan total debit dan kredit masing-masing. Laporan ini digunakan untuk memverifikasi bahwa pembukuan seimbang sebelum menghasilkan laporan keuangan lainnya.

### Tampilan

| Kolom | Deskripsi |
| - | - |
| **Kode Akun** | Kode COA (misal 1-1100) |
| **Nama Akun** | Nama akun sesuai COA |
| **Tipe** | asset / liability / equity / revenue / expense |
| **Total Debit** | SUM semua debit di jurnal |
| **Total Kredit** | SUM semua kredit di jurnal |
| **Status** | Badge "Seimbang" atau "Tidak Seimbang" |

### Color Coding

Setiap tipe akun memiliki warna yang berbeda untuk memudahkan identifikasi:

| Tipe | Warna |
| - | - |
| Asset | Biru |
| Liability | Merah |
| Equity | Hijau |
| Revenue | Emerald |
| Expense | Amber |

### Validasi

Di bagian bawah laporan, total debit dan kredit dijumlahkan dan dibandingkan. Jika selisih > Rp 1, status "Tidak Seimbang" ditampilkan sebagai peringatan bahwa ada ketidaksesuaian dalam pembukuan.

***

## Laporan Anggaran vs Aktual

### Arsitektur Pencocokan

Laporan ini membandingkan anggaran yang sudah dibuat dengan realisasi aktual. Sistem menggunakan `CATEGORY_ALIASES` untuk fuzzy matching antara kategori budget dan kategori expense aktual:

```mermaid theme={null}
flowchart LR
    B[Budget Item<br/>kategori: salary] --> M{CATEGORY<br/>ALIASES}
    F[Financial Record<br/>kategori: gaji] --> M
    M -->|Match| R[Variansi & Usage %]
```

### Contoh Alias

| Kategori Budget | Alias yang Dicocokkan |
| - | - |
| `salary` | `gaji`, `upah`, dll |
| `raw_material` | `bahan baku`, `material`, dll |
| `operational` | `operasional`, `listrik`, `air`, dll |
| `production_cost` | `produksi`, `manufacturing`, dll |
| `travel` | `perjalanan`, `transport`, dll |

### Metrik Per Item

| Metrik | Perhitungan | Keterangan |
| - | - | - |
| **Anggaran** | `budget.amount` | Nominal anggaran |
| **Aktual** | SUM expense yang match | Realisasi berdasarkan transaksi |
| **Variansi** | `anggaran - aktual` | Selisih (positif = hemat) |
| **Usage %** | `(aktual / anggaran) × 100%` | Persentase pemakaian |

### Status Badge

| Status | Kondisi | Warna |
| - | - | - |
| **Aman** (ok) | Usage \< 80% | Hijau |
| **Perhatian** (warning) | 80% ≤ Usage ≤ 100% | Kuning |
| **Melebihi** (over) | Usage > 100% | Merah |

### Visualisasi Chart

Laporan ini menampilkan **Recharts `<BarChart>`** dengan grouped bars:

| Bar | Warna | Data Key |
| - | - | - |
| Anggaran | Biru | `budget` |
| Aktual | Orange | `actual` |

Progress bar juga ditampilkan per item untuk visualisasi persentase pemakaian secara cepat.

***

## Fitur Cetak & Export

### Print Support

Setiap laporan mendukung cetak langsung via `window.print()`:

* Tombol **"Cetak"** di toolbar laporan
* Header print-only menampilkan nama perusahaan dan rentang periode
* Elemen non-esensial disembunyikan via atribut `data-print-hide`
* Wrapper `print-report` mengontrol layout saat print
* CSS `@media print` memastikan hasil cetak rapi tanpa elemen UI

### Format Export

| Format | Kegunaan |
| - | - |
| **PDF** | Arsip dan presentasi manajemen |
| **Excel** | Analisis lanjutan dan manipulasi data |
| **CSV** | Integrasi dengan sistem lain |
| **Print** | Cetak langsung dari browser |

***

## Integrasi Cross-Module

```mermaid theme={null}
graph LR
    POS[POS / Kasir] --> FR[Financial Record]
    MFG[Manufacturing] --> JE[GL Journal Entry]
    EXP[Expense] --> FR
    INV[Invoice] --> FR
    BUD[Budget Planner] --> BD[Budget]
    
    FR --> RPT[Financial Reports]
    JE --> RPT
    BD --> RPT
    ACC[GL Account/COA] --> RPT
```

Laporan keuangan mengonsumsi data dari seluruh modul keuangan. Jurnal GL dari manufacturing dan expense, Financial Record dari POS dan invoice, serta Budget dari Budget Planner — semuanya mengalir ke mesin pelaporan untuk dihasilkan sebagai laporan terpadu.

## Best Practices

### Tutup Buku Bulanan

1. Pastikan seluruh transaksi sudah tercatat dan diposting
2. Rekonsiliasi semua rekening bank
3. Review Neraca Saldo — pastikan status "Seimbang"
4. Generate Laporan Laba Rugi dan Neraca
5. Analisis variansi dari Anggaran vs Aktual

### Analisis Keuangan

* Bandingkan laporan dengan anggaran untuk identifikasi penyimpangan
* Bandingkan antar periode untuk melihat tren
* Perhatikan status completeness (Audited vs Provisional)
* Gunakan data Laba Rugi untuk evaluasi profitabilitas

### Kepatuhan

* Simpan laporan dalam arsip untuk audit
* Pastikan persamaan akuntansi di Neraca selalu seimbang
* Prepare laporan pajak dari data yang sudah diaudit
* Review Trial Balance sebelum closing periode

***

## Entity Relationship Diagram

```mermaid theme={null}
erDiagram
    GLAccount ||--o{ GLJournalEntry : "line_items.account_id"
    GLAccount ||--o{ GLAccount : "parent_account_id (hirarki COA)"
    GLJournalEntry ||--o{ FinancialRecord : "reference_id / reference_type"
    FinancialRecord }o--|| GLAccount : "account_id (rekening)"
    FinancialRecord }o--o| Budget : "category matching (CATEGORY_ALIASES)"
    Budget }o--|| GLAccount : "category → COA mapping"
    FinancialReportSnapshot }o--|| GLJournalEntry : "report_data (sumber)"
    FinancialReportSnapshot }o--|| FinancialRecord : "report_data (sumber fallback)"
    FinancialReportSnapshot }o--|| Budget : "report_data (budget_vs_actual)"
    FinancialReportSnapshot }o--|| GLAccount : "report_data (COA referensi)"

    GLAccount {
        string id PK
        string company_id FK
        string account_code UK
        string account_name
        string account_type "asset|liability|equity|revenue|expense"
        string category
        string sub_category
        string parent_account_id FK
        string normal_balance "debit|credit"
        boolean is_active
        string description
        number level "0=header, 1=main, 2=sub"
    }

    GLJournalEntry {
        string id PK
        string company_id FK
        date entry_date
        string reference_number
        string reference_type "manual|invoice|purchase_order|transfer|expense"
        string reference_id FK
        string description
        array line_items "[{account_id, account_code, debit, credit, description}]"
        number total_debit
        number total_credit
        boolean is_balanced
        string status "draft|posted|reversed"
        date posted_date
        string posted_by FK
        string notes
    }

    FinancialRecord {
        string id PK
        string user_id FK
        string company_id FK
        string account_id FK
        string type "income|expense|transfer"
        number amount
        string category
        string description
        datetime date
        string attachment_url
        string source "manual|ai_text|ai_scan|pos|manufacturing|distribution|recall|stock_opname"
        string mode "personal|business"
        string transfer_to_account_id FK
        number transfer_fee
        string reference_id FK
        string reference_type
        string idempotency_key UK
        boolean is_inventory_material
        number channel_fee
        number cogs_amount
        number tax_amount
    }

    FinancialReportSnapshot {
        string id PK
        string company_id FK
        string report_type "profit_loss|balance_sheet|cash_flow|budget_vs_actual|trial_balance|custom"
        string report_name
        date start_date
        date end_date
        string generated_by_user_id FK
        datetime generated_date
        object report_data "JSON snapshot hasil laporan"
        string template_id FK
        string notes
    }

    Budget {
        string id PK
        string user_id FK
        string company_id FK
        string name
        string description
        string category
        number planned_amount
        number actual_amount
        string period "monthly|quarterly|yearly|custom"
        date start_date
        date end_date
        string status "active|completed|archived"
        number alert_threshold
    }
```

***

## Tabel Schema

### FinancialReportSnapshot

Snapshot hasil generate laporan keuangan. Menyimpan data laporan dalam format JSON agar dapat di-replay tanpa menghitung ulang dari sumber data.

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `id` | `string` | Ya (auto) | Primary key |
| `company_id` | `string` | **Ya** | ID perusahaan pemilik laporan |
| `report_type` | `string` (enum) | **Ya** | Jenis laporan: `profit_loss`, `balance_sheet`, `cash_flow`, `budget_vs_actual`, `trial_balance`, `custom` |
| `report_name` | `string` | **Ya** | Nama laporan yang di-generate (misal: "Laba Rugi Q1 2026") |
| `start_date` | `date` | **Ya** | Tanggal mulai periode laporan |
| `end_date` | `date` | **Ya** | Tanggal akhir periode laporan |
| `generated_by_user_id` | `string` | **Ya** | ID user yang men-generate laporan |
| `generated_date` | `datetime` | **Ya** | Timestamp kapan laporan di-generate |
| `report_data` | `object` (JSON) | **Ya** | Snapshot data laporan lengkap (semua metrik, baris laporan, total) |
| `template_id` | `string` | Tidak | ID template laporan (jika menggunakan template kustom) |
| `notes` | `string` | Tidak | Catatan tambahan untuk laporan |

### FinancialRecord

Buku kas utama yang mencatat semua transaksi keuangan dari 8 sumber berbeda. Merupakan fallback source untuk laporan Laba Rugi ketika jurnal GL belum lengkap.

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `id` | `string` | Ya (auto) | Primary key |
| `user_id` | `string` | **Ya** | ID pengguna pencatat |
| `company_id` | `string` | Tidak | ID perusahaan (null untuk personal) |
| `account_id` | `string` | Tidak | ID rekening/kantong sumber dana |
| `type` | `string` (enum) | **Ya** | Jenis transaksi: `income`, `expense`, `transfer` |
| `amount` | `number` | **Ya** | Jumlah transaksi |
| `category` | `string` | Tidak | Kategori transaksi (matching ke budget via `CATEGORY_ALIASES`) |
| `description` | `string` | Tidak | Deskripsi singkat transaksi |
| `date` | `datetime` | **Ya** | Tanggal dan waktu transaksi |
| `attachment_url` | `string` | Tidak | URL bukti transaksi (struk/faktur) |
| `source` | `string` (enum) | Tidak | Sumber entri: `manual`, `ai_text`, `ai_scan`, `pos`, `manufacturing`, `distribution`, `recall`, `stock_opname` |
| `mode` | `string` (enum) | Tidak | Mode pencatatan: `personal`, `business` |
| `transfer_to_account_id` | `string` | Tidak | ID rekening tujuan (khusus `type=transfer`) |
| `transfer_fee` | `number` | Tidak | Biaya transfer (default: 0) |
| `reference_id` | `string` | Tidak | ID referensi dokumen sumber (invoice, POS, expense) |
| `reference_type` | `string` (enum) | Tidak | Tipe referensi: `invoice_payment`, `pos_transaction`, `expense`, `manual`, `transfer`, `production_order`, `distribution_shipment`, `distribution_return`, `batch_recall`, `stock_opname` |
| `idempotency_key` | `string` | Tidak | Kunci idempoten untuk mencegah duplikasi |
| `is_inventory_material` | `boolean` | Tidak | Flag bahan baku persediaan (anti double-counting, default: false) |
| `channel_fee` | `number` | Tidak | Potongan biaya marketplace / platform fee (default: 0) |
| `cogs_amount` | `number` | Tidak | HPP/COGS yang dibekukan saat transaksi POS untuk perhitungan laba kotor |
| `tax_amount` | `number` | Tidak | Jumlah pajak (PPN keluaran untuk revenue) |

### GLJournalEntry

Jurnal umum General Ledger. Sumber utama (primary source) untuk laporan Laba Rugi. Hanya entry berstatus `posted` yang digunakan dalam perhitungan laporan.

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `id` | `string` | Ya (auto) | Primary key |
| `company_id` | `string` | **Ya** | ID perusahaan |
| `entry_date` | `date` | **Ya** | Tanggal entri jurnal |
| `reference_number` | `string` | Tidak | Nomor referensi (misal: TRX-001, INV-001) |
| `reference_type` | `string` (enum) | Tidak | Tipe referensi: `manual`, `invoice`, `purchase_order`, `transfer`, `expense` |
| `reference_id` | `string` | Tidak | ID dokumen sumber |
| `description` | `string` | **Ya** | Deskripsi jurnal |
| `line_items` | `array` | **Ya** | Detail baris jurnal: `[{account_id, account_code, debit, credit, description}]` |
| `total_debit` | `number` | Tidak | Total debit (default: 0) |
| `total_credit` | `number` | Tidak | Total kredit (default: 0) |
| `is_balanced` | `boolean` | Tidak | Apakah `total_debit = total_credit` (default: false) |
| `status` | `string` (enum) | Tidak | Status jurnal: `draft`, `posted`, `reversed` (default: `draft`) |
| `posted_date` | `date` | Tidak | Tanggal posting ke GL |
| `posted_by` | `string` | Tidak | ID user yang memposting |
| `notes` | `string` | Tidak | Catatan tambahan |

### GLAccount

Chart of Accounts (COA) dengan struktur hierarki 3 level. Digunakan untuk klasifikasi akun di Neraca, Neraca Saldo, dan mapping ke jurnal GL.

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `id` | `string` | Ya (auto) | Primary key |
| `company_id` | `string` | **Ya** | ID perusahaan |
| `account_code` | `string` | **Ya** | Kode akun unik (misal: 1-1100, 1000, 2100) |
| `account_name` | `string` | **Ya** | Nama akun |
| `account_type` | `string` (enum) | **Ya** | Tipe akun: `asset`, `liability`, `equity`, `revenue`, `expense` |
| `category` | `string` | Tidak | Kategori akun (misal: Current Asset, Fixed Asset, Receivable) |
| `sub_category` | `string` | Tidak | Sub-kategori akun |
| `parent_account_id` | `string` | Tidak | ID akun parent untuk hierarki COA |
| `normal_balance` | `string` (enum) | **Ya** | Saldo normal: `debit` atau `credit` |
| `is_active` | `boolean` | Tidak | Status aktif akun (default: true) |
| `description` | `string` | Tidak | Deskripsi akun |
| `level` | `number` | Tidak | Level hierarki: 0=header, 1=main, 2=sub (default: 0) |

***

## State Machine — Siklus Hidup Laporan

```mermaid theme={null}
stateDiagram-v2
    [*] --> Draft: User membuka tab laporan
    Draft --> Computing: Trigger generate (pilih periode + klik)
    Computing --> EvaluatingSource: evaluateCompleteness()
    EvaluatingSource --> PrimaryMode: GL Revenue exist?
    EvaluatingSource --> FallbackMode: GL Revenue kosong
    PrimaryMode --> Generating: Hitung dari GLJournalEntry (posted)
    FallbackMode --> Generating: Hitung dari FinancialRecord
    Generating --> Snapshotting: Simpan FinancialReportSnapshot
    Snapshotting --> Generated: Status = audited / provisional
    Generated --> Exporting: User klik Export/Print
    Exporting --> Generated: Kembali ke tampilan
    Generated --> Archived: Periode ditutup (closing)
    Archived --> [*]

    note right of Generating
        4 laporan paralel:
        P&L, Neraca, Neraca Saldo,
        Anggaran vs Aktual
    end note

    note right of Snapshotting
        report_data disimpan
        sebagai JSON blob
        untuk replay tanpa
        hitung ulang
    end note
```

### Status Completeness

| Status | Badge | Kondisi | Implikasi |
| - | - | - | - |
| **Audited** | `ShieldCheck` | Data bersumber dari `GLJournalEntry` berstatus `posted` | Laporan dapat diandalkan untuk audit eksternal |
| **Provisional** | `AlertCircle` | Data bersumber dari `FinancialRecord` (fallback) | Belum diaudit penuh; perlu posting jurnal GL |

***

## Sequence Diagrams

### 1. Generate Laporan Keuangan

```mermaid theme={null}
sequenceDiagram
    actor User as User / Finance
    participant UI as ReportsPage
    participant Cache as cachedRequest
    participant API as Base44 API
    participant Engine as Dual-Source Engine
    participant Logic as financeLogic
    participant Snap as FinancialReportSnapshot

    User->>UI: Pilih periode & tab laporan
    UI->>Cache: loadAllData(company_id)
    par Fetch Paralel
        Cache->>API: GET GLAccount?company_id=X
        Cache->>API: GET GLJournalEntry?company_id=X&status=posted
        Cache->>API: GET Budget?company_id=X
        Cache->>API: GET FinancialRecord?company_id=X
    end
    API-->>Cache: 4 response
    Cache-->>UI: Data terkumpul

    UI->>Engine: generateReport(type, period, data)
    Engine->>Logic: evaluateCompleteness(GL entries, FR)
    Logic-->>Engine: { source: "gl" | "buku_kas", status: "audited" | "provisional" }

    alt Primary Mode (GL)
        Engine->>Engine: Hitung dari GLJournalEntry posted
    else Fallback Mode (Buku Kas)
        Engine->>Engine: Hitung dari FinancialRecord
    end

    Engine-->>UI: { metrics, lines, completeness }
    UI->>Snap: Save snapshot (report_data JSON)
    Snap-->>UI: Snapshot tersimpan
    UI-->>User: Tampilkan laporan + badge status
```

### 2. Export & Cetak Laporan

```mermaid theme={null}
sequenceDiagram
    actor User as User / Finance
    participant UI as ReportsPage
    participant Export as Export Engine
    participant Printer as Browser Print

    User->>UI: Klik tombol "Cetak"
    UI->>UI: Tampilkan header print-only (nama perusahaan + periode)
    UI->>UI: Sembunyikan elemen non-esensial (data-print-hide)
    UI->>Printer: window.print()
    Printer-->>User: Dialog cetak browser

    User->>UI: Klik "Export PDF"
    UI->>Export: generatePDF(report_data, format)
    Export-->>User: Download file PDF

    User->>UI: Klik "Export Excel"
    UI->>Export: generateExcel(report_data, format)
    Export-->>User: Download file .xlsx

    User->>UI: Klik "Export CSV"
    UI->>Export: generateCSV(report_data, format)
    Export-->>User: Download file .csv
```

### 3. Laporan Anggaran vs Aktual (Budget Matching)

```mermaid theme={null}
sequenceDiagram
    actor User as User / Finance
    participant UI as BudgetVsActualReport
    participant Alias as CATEGORY_ALIASES
    participant Budget as Budget Entity
    participant FR as FinancialRecord

    User->>UI: Pilih periode & tab "Anggaran vs Aktual"
    UI->>Budget: GET Budget (company_id, period)
    UI->>FR: GET FinancialRecord (type=expense, period)

    loop Setiap Budget Item
        UI->>Alias: fuzzyMatch(budget.category)
        Alias-->>UI: Daftar alias (salary → gaji, upah, ...)
        UI->>FR: Filter expense WHERE category IN aliases
        FR-->>UI: Matched records
        UI->>UI: Hitung: aktual = SUM(matched.amount)
        UI->>UI: Hitung: variansi = anggaran - aktual
        UI->>UI: Hitung: usage% = (aktual / anggaran) × 100%
        UI->>UI: Tentukan status badge (aman/perhatian/melebihi)
    end

    UI-->>User: Tabel variansi + BarChart grouped bars
```

***

## Enum Tables

### report\_type (FinancialReportSnapshot)

| Nilai | Label | Deskripsi |
| - | - | - |
| `profit_loss` | Laba Rugi | Laporan pendapatan, HPP, beban operasional, dan laba bersih |
| `balance_sheet` | Neraca | Posisi aset, liabilitas, dan ekuitas pada tanggal tertentu |
| `cash_flow` | Arus Kas | Aliran kas masuk dan keluar (belum diimplementasi penuh) |
| `budget_vs_actual` | Anggaran vs Aktual | Perbandingan anggaran dengan realisasi beserta variansi |
| `trial_balance` | Neraca Saldo | Daftar semua akun GL dengan total debit/kredit untuk verifikasi keseimbangan |
| `custom` | Kustom | Laporan berdasarkan template yang dibuat user |

### source (FinancialRecord)

| Nilai | Label | Deskripsi |
| - | - | - |
| `manual` | Manual | Dicatat langsung oleh user |
| `ai_text` | AI Text | Di-extract dari input teks oleh AI |
| `ai_scan` | AI Scan | Di-extract dari foto/scan struk oleh AI |
| `pos` | POS | Otomatis dari transaksi kasir/POS |
| `manufacturing` | Manufacturing | Otomatis dari produksi/manufaktur |
| `distribution` | Distribution | Otomatis dari pengiriman distribusi |
| `recall` | Recall | Otomatis dari penarikan produk (batch recall) |
| `stock_opname` | Stock Opname | Otomatis dari penyesuaian stok |

### reference\_type (FinancialRecord)

| Nilai | Label | Deskripsi |
| - | - | - |
| `invoice_payment` | Pembayaran Invoice | Referensi ke invoice yang dibayar |
| `pos_transaction` | Transaksi POS | Referensi ke transaksi kasir |
| `expense` | Expense | Referensi ke catatan pengeluaran |
| `manual` | Manual | Tanpa referensi dokumen |
| `transfer` | Transfer | Referensi ke transfer antar rekening |
| `production_order` | Production Order | Referensi ke order produksi |
| `distribution_shipment` | Distribution Shipment | Referensi ke pengiriman distribusi |
| `distribution_return` | Distribution Return | Referensi ke retur distribusi |
| `batch_recall` | Batch Recall | Referensi ke penarikan batch produk |
| `stock_opname` | Stock Opname | Referensi ke hasil stock opname |

### reference\_type (GLJournalEntry)

| Nilai | Label | Deskripsi |
| - | - | - |
| `manual` | Manual | Jurnal entri manual |
| `invoice` | Invoice | Di-generate dari invoice |
| `purchase_order` | Purchase Order | Di-generate dari PO |
| `transfer` | Transfer | Di-generate dari transfer |
| `expense` | Expense | Di-generate dari expense |

### period (Budget)

| Nilai | Label | Deskripsi |
| - | - | - |
| `monthly` | Bulanan | Periode satu bulan |
| `quarterly` | Kuartalan | Periode tiga bulan |
| `yearly` | Tahunan | Periode satu tahun |
| `custom` | Kustom | Rentang tanggal ditentukan user |

### account\_type (GLAccount)

| Nilai | Label | Saldo Normal | Warna di Trial Balance |
| - | - | - | - |
| `asset` | Aset | Debit | Biru |
| `liability` | Liabilitas | Kredit | Merah |
| `equity` | Ekuitas | Kredit | Hijau |
| `revenue` | Pendapatan | Kredit | Emerald |
| `expense` | Beban | Debit | Amber |

### status (GLJournalEntry)

| Nilai | Label | Deskripsi |
| - | - | - |
| `draft` | Draft | Jurnal belum diposting; belum mempengaruhi saldo akun |
| `posted` | Posted | Jurnal sudah diposting; mempengaruhi saldo akun dan digunakan di laporan |
| `reversed` | Reversed | Jurnal dibalik (reversal); tidak lagi aktif |

### completeness (Laporan)

| Nilai | Badge | Ikon | Deskripsi |
| - | - | - | - |
| `audited` | Audited | `ShieldCheck` | Data lengkap dari jurnal GL yang sudah diposting |
| `provisional` | Provisional | `AlertCircle` | Data berdasarkan buku kas, belum diaudit penuh |

### budget\_status (Budget)

| Nilai | Label | Deskripsi |
| - | - | - |
| `active` | Aktif | Anggaran sedang berjalan |
| `completed` | Selesai | Periode anggaran telah berakhir |
| `archived` | Diarsipkan | Anggaran tidak aktif, disimpan sebagai arsip |

### Format Export

| Format | Kegunaan | Keterangan |
| - | - | - |
| PDF | Arsip dan presentasi manajemen | Layout print-ready dengan header perusahaan |
| Excel (.xlsx) | Analisis lanjutan | Data terstruktur per sheet, dapat difilter |
| CSV | Integrasi sistem lain | Format universal, dapat diimpor ke sistem akuntansi |
| Print | Cetak langsung dari browser | Via `window.print()` dengan CSS `@media print` |

***

## RBAC — Hak Akses Laporan Keuangan

| Peran | Lihat Laporan | Generate Laporan | Export/Cetak | Hapus Snapshot | Kelola COA | Posting Jurnal |
| - | :-: | :-: | :-: | :-: | :-: | :-: |
| **Admin** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| **Finance Manager** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| **Finance Staff** | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| **Accounting** | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ (draft) |
| **Viewer / Auditor** | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
| **Owner** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |

### Catatan RBAC

* **Admin / Owner** memiliki akses penuh ke seluruh entitas keuangan termasuk manipulasi COA dan jurnal
* **Finance Staff** dapat melihat dan generate laporan serta export, namun tidak dapat menghapus snapshot atau mengubah COA
* **Accounting** dapat memposting jurnal draft namun tidak dapat mengubah struktur COA
* **Viewer / Auditor** hanya memiliki akses baca terhadap laporan yang sudah di-generate
* RLS pada `FinancialRecord` memastikan user hanya melihat data sesuai `company_id` atau data miliknya sendiri
* RLS pada `FinancialReportSnapshot`, `GLJournalEntry`, dan `GLAccount` menggunakan filter `company_id` untuk isolasi multi-tenant


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.