> ## 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.

# Company 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: "Company Reports"
description: "Pusat laporan perusahaan dengan 14 tab — POS Reports (10 jenis), Sales (9 channel), Finance, HR, Forecasting, QC, Data Quality, dan AI Insights."
---------------------------------------------------------------------------------------------------------------------------------------------------------------

# Company Reports

<img src="https://mintcdn.com/quinnofspicy/e4f_upKhVWcjsUmM/docs/mintlify/screenshots/analytics/company-reports.png?fit=max&auto=format&n=e4f_upKhVWcjsUmM&q=85&s=4863d6a33febb8d87bbc3f8d26692e57" alt="Company Reports" width="1920" height="1080" data-path="docs/mintlify/screenshots/analytics/company-reports.png" />

Company Reports adalah pusat pelaporan paling komprehensif di SNISHOP ERP. Dengan 14 tab laporan, 10 jenis POS report, 9 sales channel, dan 12 parallel API calls, halaman ini menghasilkan laporan dari level operasional hingga strategis — lengkap dengan forecasting engine, quality control, data quality audit, dan AI insights.

## Arsitektur 14-Tab

```mermaid theme={null}
graph TD
    A[CompanyReports.jsx<br/>~388KB] --> B[12 Parallel API Calls]
    
    B --> B1[CompanyPOSTransaction]
    B --> B2[FinancialRecord]
    B --> B3[CompanyPOSProduct]
    B --> B4[CompanyMember]
    B --> B5[CompanyPayroll]
    B --> B6[Customer]
    B --> B7[CompanyAttendance]
    B --> B8[CompanyLeave]
    B --> B9[Project]
    B --> B10[Asset]
    B --> B11[Inventory]
    B --> B12[StockMovement]
    
    A --> C[14 Tab Display]
    
    C --> T1[Overview]
    C --> T2[POS Reports<br/>10 jenis]
    C --> T3[POS Detail]
    C --> T4[Sales<br/>9 channel]
    C --> T5[Finance]
    C --> T6[Cashier Ranking]
    C --> T7[HR]
    C --> T8[Projects]
    C --> T9[Inventory]
    C --> T10[Therapist]
    C --> T11[Forecasting]
    C --> T12[QC]
    C --> T13[Data Quality]
    C --> T14[AI Insights]
```

## 10 Jenis POS Report

| # | Report Type | Grouping | Kegunaan |
| - | - | - | - |
| 1 | `per_item` | Per produk | Produk terlaris |
| 2 | `per_category` | Per kategori | Performa kategori |
| 3 | `per_brand` | Per brand | Performa brand |
| 4 | `per_customer` | Per pelanggan | Analisis pembeli |
| 5 | `per_cashier` | Per kasir | Ranking kasir |
| 6 | `per_location` | Per lokasi | Performa cabang |
| 7 | `per_payment` | Per metode bayar | Preferensi pembayaran |
| 8 | `per_hour` | Per jam | Peak hours |
| 9 | `daily_summary` | Per hari | Ringkasan harian |
| 10 | `profit_analysis` | Analisis profit | Margin per item |

## 9 Sales Channel

| Channel | Ikon | Deskripsi |
| - | - | - |
| `OFFLINE` | 🏪 | Penjualan langsung di toko |
| `SHOPEE` | 🟠 | Marketplace Shopee |
| `TOKOPEDIA` | 🟢 | Marketplace Tokopedia |
| `TIKTOK` | ⚫ | TikTok Shop |
| `GRAB` | 🟩 | GrabFood |
| `GOJEK` | 🟢 | GoFood |
| `WHATSAPP` | 💬 | Order via WhatsApp |
| `WEBSITE` | 🌐 | Website e-commerce |
| `OTHER` | 📦 | Channel lainnya |

## Filter & Toggle

### Multi-Filter

| Filter | Tipe | Deskripsi |
| - | - | - |
| Kasir | Multi-select | Include/exclude kasir tertentu |
| Sales Channel | Select | Filter per channel |
| Kategori | Select | Filter per kategori produk |
| Metode Pembayaran | Select | Filter per metode |
| Lokasi | Select | Filter per lokasi |
| Status | Select | Filter per status transaksi |
| Fulfillment | Select | Filter per status pemenuhan |
| Karyawan | Select | Filter per karyawan |
| Tipe Pelanggan | Select | Filter per tipe |
| Sumber Order | Select | Filter per sumber |
| Tanggal | Date range | Shortcut: hari ini, minggu ini, bulan ini |

### Toggle (Persisted ke localStorage)

| Toggle | Fungsi |
| - | - |
| `includeShippingCost` | Include biaya ongkir di revenue |
| `includeOperationalCost` | Include biaya operasional di expense |

### Split Payment

Transaksi dengan multi-tender diselesaikan via `resolvePaymentTenders()` untuk akurasi laporan pembayaran.

## Tab Overview

Dashboard ringkasan dengan `OverviewTab.jsx`:

| Elemen | Visualisasi |
| - | - |
| Revenue Trend | AreaChart + LineChart |
| Category Breakdown | PieChart |
| Daily Summary | BarChart |

## Tab Finance

Dual-source calculation (GL-first, FinancialRecord fallback):

| Metrik | Sumber |
| - | - |
| Total Revenue | GL credit-debit atau FinancialRecord |
| Total Expense | GL debit-credit atau FinancialRecord |
| Channel Fees | Sum biaya platform per channel |
| Cash Inflow | Arus kas masuk |
| Gross Profit | Revenue - COGS |
| Net Settlement | Revenue - fees - COGS |

## Tab HR

Metrik SDM yang dihitung:

| Metrik | Perhitungan |
| - | - |
| `totalEmployees` | Count `CompanyMember` |
| `activeEmployees` | Filter `status='active'` |
| `turnoverRate` | `(keluar / total) x 100%` |
| `totalPayrollCost` | Sum `CompanyPayroll.net_salary` |
| `avgSalary` | `totalPayroll / totalEmployees` |
| `attendanceRate` | `(hadir / total_hari_kerja) x 100%` |
| `lateCount` | Count terlambat |
| `absentCount` | Count tidak hadir |

## Tab Forecasting

```mermaid theme={null}
flowchart TD
    A[Historical Data] --> B[buildRealForecast<br/>realForecastPolicy.js]
    B --> C[Linear Regression<br/>+ Moving Average<br/>+ Seasonal Adjustment]
    C --> D[Horizon: 3 Bulan]
    D --> E[LineChart:<br/>Historical + Forecast]
    
    B --> F[Trend Analysis]
    F --> F1[Direction: ↑/↓/→]
    F --> F2[Percent Change]
    F --> F3[Monthly Growth Rate]
    F --> F4[Volatility Index]
```

## Tab QC (Quality Control)

`QCReportTab.jsx` memuat data dari `listQualityChecks` server function:

| Filter | Opsi |
| - | - |
| Search Supplier | Text search |
| Status | `overall_status` filter |
| Time | 30 hari, 90 hari, tahun ini |

**Chart:** Stacked BarChart — Disetujui (hijau), Ditolak (merah), Menunggu (kuning)

## Tab Data Quality

`DataQualityDashboard.jsx` memonitor kelengkapan data:

| Aspek | Validasi |
| - | - |
| Catalog Integrity | `auditCatalogIntegrity()` |
| Supplier Validation | `calculateSupplierValidationScore()` |
| Data Completeness | Per-module scoring |

## Tab AI Insights

`AIInsightsEngine.jsx` — analisis AI 3 level:

```mermaid theme={null}
flowchart TD
    A[Data Input] --> B[Data Sufficiency Scoring<br/>0-100]
    B --> B1[Transaction Volume<br/>35 poin]
    B --> B2[Finance Records<br/>20 poin]
    B --> B3[Inventory Data<br/>25 poin]
    B --> B4[Stock Movements<br/>20 poin]
    
    B --> C{Score cukup?}
    C --> |Ya| D[Invoke_LLM<br/>+ Real Data Context]
    C --> |Tidak| E[Warning:<br/>Data tidak cukup]
    
    D --> F[3-Level Analysis]
    F --> F1[Descriptive:<br/>Apa yang terjadi]
    F --> F2[Diagnostic:<br/>Mengapa terjadi]
    F --> F3[Predictive:<br/>Apa yang akan terjadi<br/>+ Rekomendasi]
    
    F --> G[ComposedChart:<br/>Aktual + Proyeksi]
```

## Sub-Komponen

| Komponen | Baris | Fungsi |
| - | - | - |
| `ForecastingEngine.jsx` | - | Linear Regression + MA + Seasonal |
| `QCReportTab.jsx` | - | Quality control report |
| `SalesChannelDetailCard.jsx` | - | 16 channel definitions + emoji |
| `DataQualityDashboard.jsx` | - | Data completeness audit |
| `AIInsightsEngine.jsx` | - | 3-level AI analysis |
| `OverviewTab.jsx` | - | Overview sub-tab |

## Realtime Sync

| Mekanisme | Fungsi |
| - | - |
| `BroadcastChannel API` | Cross-tab sync |
| `useRealtimeRefresh` hook | Live data updates |
| `globalCache` | Instant display + background refresh |
| `cachedRequest` | Throttled API calls |

## Cara Akses

Dari sidebar, klik menu **Analytics** > **Company Reports**. Atau dari Dashboard Analytics, klik tab **Laporan**.

## Flow Penggunaan

1. Buka Company Reports dari sidebar
2. Pilih tab laporan yang diinginkan (14 tab tersedia)
3. Atur filter (periode, lokasi, kasir, channel, dll)
4. Preview laporan di layar
5. Untuk POS Reports: pilih jenis report (per item/category/brand/dll)
6. Untuk Forecasting: pilih metrik dan horizon
7. Export via browser Print (PDF) atau CSV

## Tips

* Gunakan POS Report `per_hour` untuk identifikasi peak hours dan optimasi shift
* Sales Channel detail membantu negosiasi dengan platform marketplace
* Forecasting paling akurat dengan data historis minimal 6 bulan
* Data Quality tab membantu identifikasi data yang perlu dilengkapi sebelum analisis
* AI Insights memerlukan data sufficiency score yang cukup untuk hasil optimal

***

## Diagram Relasi Entitas Laporan Perusahaan

```mermaid theme={null}
erDiagram
    Company ||--o{ CompanyPOSTransaction : "memiliki transaksi POS"
    Company ||--o{ FinancialRecord : "mencatat transaksi keuangan"
    Company ||--o{ CompanyPOSProduct : "mengelola produk POS"
    Company ||--o{ CompanyMember : "memiliki anggota"
    Company ||--o{ CompanyPayroll : "menggaji karyawan"
    Company ||--o{ CompanyAttendance : "mencatat absensi"
    Company ||--o{ CompanyLeave : "mengelola cuti"
    Company ||--o{ Project : "menjalankan proyek"
    Company ||--o{ Asset : "memiliki aset"
    Company ||--o{ QualityCheck : "melakukan QC"
    Company ||--o{ FinancialReportSnapshot : "menyimpan snapshot laporan"
    Company ||--o{ ReportTemplate : "mendefinisikan template laporan"

    CompanyPOSTransaction }o--|| CompanyPOSProduct : "menjual produk"
    CompanyPOSTransaction }o--o| CompanyMember : "dilayani oleh kasir"
    CompanyPayroll }o--|| CompanyMember : "digaji untuk karyawan"
    CompanyAttendance }o--|| CompanyMember : "absensi karyawan"
    CompanyLeave }o--|| CompanyMember : "cuti karyawan"
    FinancialRecord }o--o| CompanyPOSTransaction : "referensi transaksi"
    FinancialReportSnapshot }o--o| ReportTemplate : "dibuat dari template"
    QualityCheck }o--o| CompanyPOSProduct : "inspeksi bahan baku"
```

## Skema Entitas

### Company

Entitas induk perusahaan yang menaungi seluruh data laporan.

| Field | Tipe | Wajib | Deskripsi |
| - | - | - | - |
| `name` | string | Ya | Nama perusahaan |
| `owner_id` | string | Ya | ID owner perusahaan |
| `owner_email` | string | Ya | Email owner |
| `owner_subscription_plan` | enum | Tidak | Plan membership owner: `free`, `pro`, `business`, `advanced`, `enterprise` |
| `description` | string | Tidak | Deskripsi perusahaan |
| `industry` | enum | Tidak | Sektor industri: `retail`, `manufacturing`, `services`, `technology`, `food_beverage`, `healthcare`, `education`, `other` |
| `address` | string | Tidak | Alamat perusahaan |
| `phone` | string | Tidak | Nomor telepon |
| `email` | string | Tidak | Email perusahaan |
| `website` | string | Tidak | Website perusahaan |
| `logo_url` | string | Tidak | URL logo perusahaan |
| `tax_id` | string | Tidak | NPWP perusahaan |
| `employee_count` | number | Tidak | Jumlah karyawan (default: 0) |
| `metadata` | object | Tidak | Data tambahan / legacy |
| `landing_page_config` | object | Tidak | Konfigurasi landing page perusahaan |
| `business_type` | string | Tidak | Kategori bisnis yang dipilih saat onboarding |
| `active_modules` | string | Tidak | JSON string berisi array ID modul aktif |
| `settings` | object | Tidak | Pengaturan perusahaan (jam kerja, cuti, pajak, dll) |

### CompanyPOSTransaction

Entitas transaksi POS — sumber utama 10 jenis POS Report dan analisis sales channel.

| Field | Tipe | Wajib | Deskripsi |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan |
| `location_id` | string | Tidak | ID lokasi gudang/toko |
| `location_name` | string | Tidak | Nama lokasi |
| `transaction_number` | string | Ya | Nomor transaksi unik |
| `invoice_number` | string | Tidak | Nomor invoice |
| `transaction_date` | date-time | Tidak | Tanggal transaksi |
| `items` | array\[object] | Ya | Item yang dibeli (product\_id, product\_name, sku, quantity, price, discount, subtotal, unit, unit\_cost, total\_cost, note) |
| `subtotal` | number | Tidak | Subtotal sebelum diskon dan pajak |
| `discount_amount` | number | Tidak | Jumlah diskon (default: 0) |
| `discount_percentage` | number | Tidak | Persentase diskon (default: 0) |
| `tax_amount` | number | Tidak | PPN atas transaksi (default: 0) |
| `total` | number | Ya | Total akhir transaksi |
| `total_amount` | number | Tidak | Total akhir (alias) |
| `payment_method` | enum | Tidak | Metode pembayaran: `cash`, `card`, `transfer`, `ewallet`, `qris`, `saldo`, `mayar`, `debt`, `manual_transfer`, `midtrans`, `tripay`, `stripe`, `paypal` |
| `payment_amount` | number | Tidak | Jumlah uang yang dibayar |
| `payments` | array\[object] | Tidak | Detail pembayaran multi-tender / split payment |
| `payment_status` | enum | Tidak | Status pembayaran: `pending`, `pending_verification`, `partially_paid`, `paid`, `failed`, `refunded`, `rejected` |
| `paid_amount` | number | Tidak | Nominal pembayaran yang telah diverifikasi (default: 0) |
| `remaining_amount` | number | Tidak | Sisa kekurangan tagihan (default: 0) |
| `excess_amount` | number | Tidak | Kelebihan nominal transfer (default: 0) |
| `change_amount` | number | Tidak | Kembalian (default: 0) |
| `payment_reference` | string | Tidak | No. referensi bukti transfer/QRIS |
| `payment_verified_by` | string | Tidak | Nama pengguna yang memverifikasi pembayaran |
| `payment_verified_at` | date-time | Tidak | Waktu verifikasi pembayaran |
| `customer_id` | string | Tidak | ID member jika ada |
| `customer_name` | string | Tidak | Nama pelanggan |
| `customer_phone` | string | Tidak | Telepon pelanggan |
| `customer_address` | string | Tidak | Alamat pelanggan |
| `points_earned` | number | Tidak | Poin yang didapat member (default: 0) |
| `points_used` | number | Tidak | Poin yang dipakai (default: 0) |
| `cashier_id` | string | Tidak | ID karyawan kasir |
| `cashier_name` | string | Tidak | Nama kasir |
| `assigned_to_id` | string | Tidak | ID karyawan yang ditugaskan |
| `assigned_to_name` | string | Tidak | Nama karyawan yang ditugaskan |
| `notes` | string | Tidak | Catatan transaksi |
| `source` | enum | Tidak | Sumber transaksi: `pos`, `online_catalog`, `website`, `marketplace`, `landing_page`, `whatsapp`, `reseller`, `b2b`, `grab`, `social_media` |
| `order_status` | enum | Tidak | Status pesanan: `pending`, `processing`, `shipped`, `delivered`, `completed`, `cancelled`, `rejected` |
| `status` | enum | Tidak | Status transaksi: `pending`, `processing`, `shipped`, `delivered`, `completed`, `failed`, `refunded`, `cancelled` |
| `tracking_number` | string | Tidak | Nomor resi pelacakan |
| `shipping_address` | string | Tidak | Alamat pengiriman |
| `sales_channel` | enum | Tidak | Channel penjualan: `offline_pos`, `offline`, `website`, `online_catalog`, `marketplace`, `landing_page`, `whatsapp`, `reseller`, `b2b`, `grab`, `social_media` |
| `metadata` | object | Tidak | Data tambahan (online order info, dll) |
| `verified_at` | date-time | Tidak | Waktu verifikasi |
| `verified_by` | string | Tidak | Verified by |
| `processed_at` | date-time | Tidak | Waktu diproses |
| `shipped_at` | date-time | Tidak | Waktu dikirim |
| `delivered_at` | date-time | Tidak | Waktu diterima |
| `cancelled_at` | date-time | Tidak | Waktu dibatalkan |

### FinancialRecord

Entitas pencatatan keuangan — sumber utama Tab Finance dan laporan profit/loss.

| Field | Tipe | Wajib | Deskripsi |
| - | - | - | - |
| `user_id` | string | Ya | ID pengguna |
| `company_id` | string | Tidak | ID perusahaan (null untuk personal) |
| `account_id` | string | Tidak | ID rekening/kantong sumber dana |
| `type` | enum | Ya | Jenis transaksi: `income`, `expense`, `transfer` |
| `amount` | number | Ya | Jumlah transaksi |
| `category` | string | Tidak | Kategori transaksi |
| `description` | string | Tidak | Deskripsi singkat |
| `date` | date-time | Ya | Tanggal transaksi |
| `attachment_url` | string | Tidak | URL bukti transaksi |
| `source` | enum | Tidak | Sumber pencatatan: `manual`, `ai_text`, `ai_scan`, `pos`, `manufacturing`, `distribution`, `recall`, `stock_opname` |
| `mode` | enum | Tidak | Mode: `personal`, `business` |
| `transfer_to_account_id` | string | Tidak | ID rekening tujuan (untuk type=transfer) |
| `transfer_fee` | number | Tidak | Biaya transfer (default: 0) |
| `reference_id` | string | Tidak | ID referensi transaksi sumber |
| `reference_type` | 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 transaksi keuangan |
| `is_inventory_material` | boolean | Tidak | Flag pembelian bahan baku (anti double-counting, default: false) |
| `channel_fee` | number | Tidak | Potongan biaya marketplace (default: 0) |
| `cogs_amount` | number | Tidak | Biaya pokok penjualan / COGS (default: 0) |
| `tax_amount` | number | Tidak | Jumlah pajak dalam amount (default: 0) |

### FinancialReportSnapshot

Entitas snapshot laporan keuangan yang telah digenerate dan disimpan.

| Field | Tipe | Wajib | Deskripsi |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan |
| `report_type` | enum | Ya | Jenis laporan: `profit_loss`, `balance_sheet`, `cash_flow`, `budget_vs_actual`, `trial_balance`, `custom` |
| `report_name` | string | Ya | Nama laporan |
| `start_date` | date | Ya | Tanggal mulai periode |
| `end_date` | date | Ya | Tanggal akhir periode |
| `generated_by_user_id` | string | Ya | ID pengguna yang generate |
| `generated_date` | date-time | Ya | Waktu laporan dibuat |
| `report_data` | object | Ya | JSON data laporan |
| `template_id` | string | Tidak | ID template yang digunakan |
| `notes` | string | Tidak | Catatan tambahan |

### ReportTemplate

Entitas template laporan yang dapat digunakan berulang untuk generate laporan.

| Field | Tipe | Wajib | Deskripsi |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan |
| `user_id` | string | Ya | ID pengguna pembuat template |
| `report_name` | string | Ya | Nama template laporan |
| `description` | string | Tidak | Deskripsi template |
| `report_type` | enum | Ya | Tipe laporan: `financial`, `sales`, `inventory`, `hr`, `project`, `custom` |
| `data_source` | string | Ya | Entity type sumber data (Invoice, FinancialRecord, dll) |
| `columns` | array\[object] | Ya | Definisi kolom laporan (field\_name, display\_label, aggregation, format) |
| `filters` | array\[object] | Tidak | Filter default (field, operator, value) |
| `group_by` | array\[string] | Tidak | Field untuk grouping |
| `sort_by` | array\[object] | Tidak | Pengurutan (field, direction: asc/desc) |
| `date_range` | object | Tidak | Rentang tanggal (start\_date, end\_date, period\_type) |
| `is_public` | boolean | Tidak | Apakah template dapat diakses publik (default: false) |
| `created_date` | date-time | Tidak | Tanggal pembuatan template |

### CompanyPOSProduct

Entitas produk POS — digunakan dalam analisis per\_item, per\_category, per\_brand, dan profit\_analysis.

| Field | Tipe | Wajib | Deskripsi |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan |
| `name` | string | Ya | Nama produk |
| `sku` | string | Tidak | SKU/Barcode produk |
| `category` | string | Tidak | Kategori produk |
| `category_key` | string | Tidak | Kategori canonical: kecil, besar, pouch, bundle, snack |
| `category_name` | string | Tidak | Label kategori canonical |
| `variant_key` | string | Tidak | Varian canonical: original, extra\_spicy, bundle |
| `variant_name` | string | Tidak | Label varian canonical |
| `variant_label` | string | Tidak | Gabungan kategori dan varian |
| `size_grams` | number | Tidak | Ukuran canonical produk dalam gram |
| `base_product_key` | string | Tidak | Kunci produk utama |
| `description` | string | Tidak | Deskripsi produk |
| `price` | number | Ya | Harga jual |
| `cost` | number | Tidak | Harga modal/beli |
| `stock` | number | Tidak | Stok saat ini (default: 0) |
| `min_stock` | number | Tidak | Minimum stok untuk alert (default: 5) |
| `image_url` | string | Tidak | URL gambar utama produk |
| `gallery` | array\[string] | Tidak | Galeri foto produk (maks 20 foto) |
| `variants` | array\[object] | Tidak | Varian produk (name, sku, price, stock) |
| `is_active` | boolean | Tidak | Status aktif produk (default: true) |
| `deactivated_at` | date-time | Tidak | Waktu SKU dinonaktifkan |
| `deactivated_by` | string | Tidak | Akun yang menonaktifkan SKU |
| `tax_rate` | number | Tidak | Persentase pajak 0-100 (default: 0) |
| `supplier` | string | Tidak | Nama supplier |
| `unit` | string | Tidak | Satuan produk (default: pcs) |
| `variant` | string | Tidak | Varian produk (Pedas, Manis, Gurih, dll) |
| `barcode` | string | Tidak | Barcode / QR Code produk (EAN-13) |
| `product_type` | enum | Tidak | Tipe produk: `finished_good`, `raw_material`, `semi_finished`, `packaging_material`, `bundle` |
| `packaging_type` | enum | Tidak | Jenis kemasan: `jar_glass`, `pouch_zipper`, `pouch_sealed`, `toples_plastic`, `bottle_plastic`, `bulk`, `other` |
| `net_weight_grams` | number | Tidak | Berat bersih isi produk dalam gram |
| `gross_weight_grams` | number | Tidak | Berat kotor termasuk kemasan dalam gram |
| `storage_condition` | enum | Tidak | Kondisi penyimpanan: `room_temperature`, `chilled`, `frozen` |
| `is_bundle` | boolean | Tidak | Flag paket bundle virtual (default: false) |
| `bundle_components` | array\[object] | Tidak | Komponen SKU penyusun bundle |
| `channel_pricing` | object | Tidak | Harga khusus per saluran penjualan |
| `is_locked` | boolean | Tidak | Data terkunci karena sudah ada transaksi (default: false) |
| `locked_at` | date-time | Tidak | Waktu penguncian data |
| `locked_by` | string | Tidak | Email user yang mengunci data |
| `lock_reason` | string | Tidak | Alasan penguncian |
| `sold_count` | number | Tidak | Total jumlah produk terjual (default: 0) |

### CompanyMember

Entitas anggota perusahaan — digunakan dalam Tab HR, cashier ranking, dan analisis per\_cashier.

| Field | Tipe | Wajib | Deskripsi |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan |
| `user_id` | string | Tidak | ID pengguna |
| `user_email` | string | Ya | Email pengguna |
| `user_name` | string | Tidak | Nama pengguna |
| `role` | enum | Tidak | Role: `owner`, `admin`, `supervisor`, `store_admin`, `stock_admin`, `finance_admin`, `hr_admin`, `transaction_admin`, `employee`, `production_operator`, `qc_inspector`, `sales_marketing`, `partner_distributor` |
| `employee_id` | string | Tidak | Link ke entitas Employee |
| `department` | string | Tidak | Departemen |
| `position` | string | Tidak | Jabatan |
| `status` | enum | Tidak | Status keanggotaan: `active`, `inactive`, `pending` |
| `joined_date` | date | Tidak | Tanggal bergabung |
| `invited_by` | string | Tidak | Email yang mengundang |
| `permissions` | object | Tidak | Hak akses detail untuk member (can\_view\_reports, can\_view\_finance, can\_view\_hr, dll) |
| `assigned_locations` | array\[string] | Tidak | Daftar ID lokasi gudang/outlet yang diizinkan |
| `working_hours` | object | Tidak | Jam kerja karyawan (start, end) |
| `salary` | number | Tidak | Gaji karyawan (opsional) |
| `notes` | string | Tidak | Catatan tambahan |

### CompanyPayroll

Entitas penggajian — sumber data utama untuk Tab HR dan perhitungan biaya SDM.

| Field | Tipe | Wajib | Deskripsi |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan |
| `employee_id` | string | Ya | ID karyawan |
| `employee_name` | string | Tidak | Nama karyawan |
| `period` | string | Ya | Periode gaji (format YYYY-MM) |
| `basic_salary` | number | Ya | Gaji pokok |
| `attendance_days` | number | Tidak | Jumlah hari hadir |
| `working_days` | number | Tidak | Total hari kerja di periode |
| `late_count` | number | Tidak | Jumlah terlambat (default: 0) |
| `absent_count` | number | Tidak | Jumlah tidak hadir (default: 0) |
| `overtime_hours` | number | Tidak | Jam lembur (default: 0) |
| `kpi_score` | number | Tidak | Skor KPI periode ini |
| `allowances` | array\[object] | Tidak | Tunjangan (name, amount) |
| `deductions` | array\[object] | Tidak | Potongan (name, amount) |
| `overtime_pay` | number | Tidak | Upah lembur (default: 0) |
| `kpi_bonus` | number | Tidak | Bonus berdasarkan KPI (default: 0) |
| `gross_salary` | number | Ya | Gaji kotor |
| `net_salary` | number | Ya | Gaji bersih |
| `status` | enum | Tidak | Status payroll: `draft`, `approved`, `paid` |
| `payment_date` | date | Tidak | Tanggal pembayaran |
| `payment_method` | enum | Tidak | Metode bayar: `bank_transfer`, `cash`, `check` |
| `notes` | string | Tidak | Catatan |

### CompanyAttendance

Entitas absensi — digunakan dalam Tab HR untuk menghitung attendanceRate, lateCount, absentCount.

| Field | Tipe | Wajib | Deskripsi |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan |
| `employee_id` | string | Ya | ID karyawan |
| `employee_name` | string | Tidak | Nama karyawan |
| `employee_email` | string | Tidak | Email karyawan |
| `date` | date | Ya | Tanggal absensi |
| `shift_id` | string | Tidak | ID shift yang dipilih |
| `shift_name` | string | Tidak | Nama shift (Pagi/Siang/Malam) |
| `clock_in_time` | date-time | Ya | Waktu clock in |
| `clock_out_time` | date-time | Tidak | Waktu clock out |
| `clock_in_photo_url` | string | Tidak | URL foto saat clock in |
| `clock_out_photo_url` | string | Tidak | URL foto saat clock out |
| `clock_in_location` | object | Tidak | Lokasi GPS clock in (latitude, longitude, accuracy) |
| `clock_out_location` | object | Tidak | Lokasi GPS clock out (latitude, longitude, accuracy) |
| `status` | enum | Tidak | Status absensi: `present`, `late`, `absent`, `sick`, `leave`, `wfh` |
| `notes` | string | Tidak | Catatan absensi |
| `total_hours` | number | Tidak | Total jam kerja |
| `overtime_hours` | number | Tidak | Jam lembur (default: 0) |
| `distance_from_office` | number | Tidak | Jarak dari kantor/geofence dalam meter |
| `location_id` | string | Tidak | ID lokasi geofence absensi |
| `location_name` | string | Tidak | Nama lokasi geofence |
| `clock_in_accuracy` | number | Tidak | Akurasi GPS clock in dalam meter |
| `clock_out_accuracy` | number | Tidak | Akurasi GPS clock out dalam meter |
| `is_manual_override` | boolean | Tidak | Flag koreksi manual berizin (default: false) |
| `override_reason` | string | Tidak | Alasan koreksi manual |
| `override_approved_by` | string | Tidak | ID approver koreksi manual |
| `override_approved_at` | date-time | Tidak | Waktu persetujuan koreksi |

### CompanyLeave

Entitas cuti karyawan — melengkapi data Tab HR.

| Field | Tipe | Wajib | Deskripsi |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan |
| `employee_id` | string | Ya | ID karyawan |
| `employee_name` | string | Tidak | Nama karyawan |
| `employee_email` | string | Tidak | Email karyawan |
| `leave_type` | enum | Ya | Jenis cuti: `annual`, `sick`, `unpaid`, `maternity`, `paternity`, `emergency` |
| `start_date` | date | Ya | Tanggal mulai cuti |
| `end_date` | date | Ya | Tanggal akhir cuti |
| `total_days` | number | Tidak | Total hari cuti |
| `reason` | string | Ya | Alasan cuti |
| `description` | string | Tidak | Keterangan tambahan (maks 1000 karakter) |
| `attachment_url` | string | Tidak | URL lampiran (surat dokter, dll) |
| `status` | enum | Tidak | Status pengajuan: `pending`, `approved`, `rejected`, `cancelled` |
| `approver_id` | string | Tidak | ID approver |
| `approver_notes` | string | Tidak | Catatan approver |
| `approved_at` | date-time | Tidak | Waktu persetujuan |

### Project

Entitas proyek — digunakan dalam Tab Projects untuk laporan kemajuan dan biaya.

| Field | Tipe | Wajib | Deskripsi |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan |
| `name` | string | Ya | Nama proyek |
| `description` | string | Tidak | Deskripsi proyek |
| `client_id` | string | Tidak | ID klien |
| `client_name` | string | Tidak | Nama klien |
| `project_manager_id` | string | Tidak | ID project manager |
| `start_date` | date | Ya | Tanggal mulai |
| `end_date` | date | Tidak | Tanggal selesai |
| `budget` | number | Tidak | Anggaran proyek |
| `actual_cost` | number | Tidak | Biaya aktual (default: 0) |
| `status` | enum | Tidak | Status: `planning`, `in_progress`, `on_hold`, `completed`, `cancelled` |
| `priority` | enum | Tidak | Prioritas: `low`, `medium`, `high`, `urgent` |
| `progress` | number | Tidak | Persentase kemajuan 0-100 (default: 0) |
| `team_members` | array\[string] | Tidak | Array ID karyawan tim |
| `milestones` | array\[object] | Tidak | Milestone proyek (name, description, due\_date, status, completed\_date) |
| `attachments` | array\[string] | Tidak | Lampiran proyek |
| `tags` | array\[string] | Tidak | Tag proyek |

### Asset

Entitas aset — digunakan dalam laporan inventaris dan depresiasi.

| Field | Tipe | Wajib | Deskripsi |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan |
| `asset_name` | string | Ya | Nama aset |
| `asset_code` | string | Ya | Kode aset unik |
| `category` | enum | Ya | Kategori aset: `computer`, `furniture`, `vehicle`, `equipment`, `building`, `other` |
| `purchase_date` | date | Ya | Tanggal pembelian |
| `purchase_cost` | number | Ya | Biaya pembelian |
| `depreciation_method` | enum | Tidak | Metode depresiasi: `straight_line`, `declining_balance` |
| `useful_life_years` | number | Tidak | Umur ekonomis dalam tahun |
| `salvage_value` | number | Tidak | Nilai sisa (default: 0) |
| `current_value` | number | Tidak | Nilai buku saat ini |
| `location` | string | Tidak | Lokasi aset |
| `assigned_to` | string | Tidak | ID karyawan yang menggunakan |
| `condition` | enum | Tidak | Kondisi: `excellent`, `good`, `fair`, `poor` |
| `maintenance_schedule` | array\[object] | Tidak | Jadwal perawatan (date, description, cost, status) |
| `status` | enum | Tidak | Status aset: `active`, `under_maintenance`, `disposed` |
| `qr_code` | string | Tidak | QR code aset |
| `image_url` | string | Tidak | URL gambar aset |
| `notes` | string | Tidak | Catatan |

### QualityCheck

Entitas quality control — sumber data utama Tab QC.

| Field | Tipe | Wajib | Deskripsi |
| - | - | - | - |
| `company_id` | string | Ya | ID perusahaan (multi-tenant) |
| `qc_number` | string | Ya | Nomor QC unik (auto-generate: QC-YYYYMMDD-XXX) |
| `purchase_order_id` | string | Tidak | ID Purchase Order terkait |
| `po_number` | string | Tidak | Nomor PO |
| `supplier_id` | string | Ya | ID supplier |
| `supplier_name` | string | Tidak | Nama supplier |
| `raw_material_id` | string | Ya | ID bahan baku yang diperiksa |
| `raw_material_name` | string | Tidak | Nama bahan baku |
| `batch_id` | string | Tidak | Batch ID bahan baku |
| `quantity_received` | number | Tidak | Jumlah yang diterima |
| `unit` | string | Tidak | Satuan |
| `qc_date` | date | Ya | Tanggal pengecekan QC |
| `qc_time` | string | Tidak | Waktu pengecekan |
| `inspector_id` | string | Tidak | ID user QC inspector |
| `inspector_name` | string | Tidak | Nama inspector |
| `checklist` | array\[object] | Tidak | Checklist digital QC (item, standard, result: pass/fail/warning/na, notes) |
| `overall_status` | enum | Tidak | Status keseluruhan: `pending`, `approved`, `rejected`, `conditional` |
| `rejection_reason` | string | Tidak | Alasan penolakan |
| `photos` | array\[string] | Tidak | URL foto dokumentasi QC |
| `temperature` | number | Tidak | Suhu bahan saat diterima (derajat C) |
| `humidity` | number | Tidak | Kelembaban (%) |
| `expiry_date_check` | enum | Tidak | Hasil cek expired: `valid`, `expired`, `near_expiry`, `no_date` |
| `approved_quantity` | number | Tidak | Jumlah disetujui masuk inventory (default: 0) |
| `rejected_quantity` | number | Tidak | Jumlah ditolak (default: 0) |
| `inventory_updated` | boolean | Tidak | Stok sudah masuk inventory (default: false) |
| `claimed_quantity` | number | Tidak | Kuantitas menurut surat jalan supplier |
| `weighed_quantity` | number | Tidak | Kuantitas hasil timbang ulang fisik |
| `delivery_variance` | number | Tidak | Selisih kuantitas: claimed - weighed (default: 0) |
| `delivery_note_number` | string | Tidak | Nomor surat jalan supplier |
| `proof_attachment_url` | string | Tidak | URL lampiran foto surat jalan |
| `unit_cost` | number | Tidak | Estimasi biaya per unit / HPP (default: 0) |
| `notes` | string | Tidak | Catatan |

## Siklus Hidup Pembuatan Laporan

```mermaid theme={null}
stateDiagram-v2
    [*] --> FilterDipilih: Pengguna memilih filter & periode
    FilterDipilih --> MengambilData: 12 parallel API calls
    MengambilData --> DataTersedia: Data berhasil dimuat
    MengambilData --> GagalMuat: Timeout / error
    GagalMuat --> MengambilData: Retry

    DataTersedia --> RenderingLaporan: Render 14 tab
    RenderingLaporan --> LaporanDitampilkan: Visualisasi chart + tabel
    
    LaporanDitampilkan --> ExportPDF: Cetak PDF via browser
    LaporanDitampilkan --> ExportCSV: Export CSV
    LaporanDitampilkan --> SnapshotDisimpan: Simpan FinancialReportSnapshot
    LaporanDitampilkan --> FilterDiubah: Pengguna mengubah filter
    
    SnapshotDisimpan --> LaporanDiarsipkan: Arsip laporan
    LaporanDiarsipkan --> [*]
    
    ExportPDF --> [*]
    ExportCSV --> [*]
    
    FilterDiubah --> MengambilData: Reload data dengan filter baru
    
    state MengambilData {
        [*] --> POS_Transaction
        [*] --> Financial_Record
        [*] --> Company_Member
        [*] --> Payroll_Data
        [*] --> Attendance_Data
        [*] --> Leave_Data
        [*] --> Product_Data
        [*] --> Project_Data
        [*] --> Asset_Data
        [*] --> Inventory_Data
        [*] --> StockMovement_Data
        [*] --> QC_Data
        POS_Transaction --> [*]
        Financial_Record --> [*]
        Company_Member --> [*]
        Payroll_Data --> [*]
        Attendance_Data --> [*]
        Leave_Data --> [*]
        Product_Data --> [*]
        Project_Data --> [*]
        Asset_Data --> [*]
        Inventory_Data --> [*]
        StockMovement_Data --> [*]
        QC_Data --> [*]
    }
```

## Diagram Sekuens: Pembuatan Laporan POS

```mermaid theme={null}
sequenceDiagram
    actor Pengguna as Pengguna (Admin/Owner)
    participant UI as CompanyReports.jsx
    participant API as Server Functions
    participant DB as Database
    participant Cache as Global Cache

    Pengguna->>UI: Buka Company Reports
    UI->>Cache: Cek cachedRequest()
    alt Data ada di cache
        Cache-->>UI: Return cached data (instant)
    else Data belum ada
        Cache-->>UI: Cache miss
    end
    UI->>API: 12 parallel API calls
    par Parallel Fetch
        API->>DB: Query CompanyPOSTransaction
        DB-->>API: Data transaksi POS
    and
        API->>DB: Query FinancialRecord
        DB-->>API: Data keuangan
    and
        API->>DB: Query CompanyPOSProduct
        DB-->>API: Data produk
    and
        API->>DB: Query CompanyMember
        DB-->>API: Data anggota
    and
        API->>DB: Query CompanyPayroll
        DB-->>API: Data payroll
    and
        API->>DB: Query CompanyAttendance
        DB-->>API: Data absensi
    and
        API->>DB: Query CompanyLeave
        DB-->>API: Data cuti
    and
        API->>DB: Query Project
        DB-->>API: Data proyek
    and
        API->>DB: Query Asset
        DB-->>API: Data aset
    and
        API->>DB: Query Inventory
        DB-->>API: Data inventaris
    and
        API->>DB: Query StockMovement
        DB-->>API: Data pergerakan stok
    and
        API->>DB: Query QualityCheck
        DB-->>API: Data QC
    end
    API-->>UI: Semua data terkumpul
    UI->>Cache: Simpan ke globalCache
    UI->>UI: resolvePaymentTenders() untuk split payment
    UI->>UI: Hitung metrik per tab (14 tab)
    UI-->>Pengguna: Tampilkan laporan lengkap
```

## Diagram Sekuens: Export Laporan

```mermaid theme={null}
sequenceDiagram
    actor Pengguna as Pengguna
    participant UI as CompanyReports.jsx
    participant Engine as ForecastingEngine / AIInsightsEngine
    participant Snapshot as FinancialReportSnapshot
    participant DB as Database

    Pengguna->>UI: Pilih tab + Atur filter
    UI->>UI: Hitung ulang metrik dengan filter baru
    UI-->>Pengguna: Tampilkan hasil

    alt Export PDF
        Pengguna->>UI: Klik Print / Ctrl+P
        UI->>UI: Format laporan untuk cetak
        UI-->>Pengguna: Dialog cetak browser (simpan PDF)
    else Export CSV
        Pengguna->>UI: Klik Export CSV
        UI->>UI: Konversi data tab ke format CSV
        UI-->>Pengguna: Unduh file .csv
    else Simpan Snapshot
        Pengguna->>UI: Simpan snapshot laporan
        UI->>Engine: Kumpulkan data + konteks laporan
        Engine->>Snapshot: Buat FinancialReportSnapshot
        Snapshot->>DB: INSERT snapshot (report_data, period, type)
        DB-->>Snapshot: Konfirmasi penyimpanan
        Snapshot-->>UI: Snapshot berhasil dibuat
        UI-->>Pengguna: Notifikasi "Laporan tersimpan"
    end
```

## Diagram Sekuens: AI Insights Engine

```mermaid theme={null}
sequenceDiagram
    actor Pengguna as Pengguna
    participant UI as AIInsightsEngine.jsx
    participant Scorer as Data Sufficiency Scorer
    participant LLM as LLM Service
    participant DB as Database

    Pengguna->>UI: Buka tab AI Insights
    UI->>Scorer: Hitung data sufficiency (0-100)
    Scorer->>DB: Query volume transaksi (35 poin)
    Scorer->>DB: Query finance records (20 poin)
    Scorer->>DB: Query inventory data (25 poin)
    Scorer->>DB: Query stock movements (20 poin)
    DB-->>Scorer: Data terkumpul
    Scorer-->>UI: Score total

    alt Score >= threshold
        UI->>LLM: Invoke LLM + Real Data Context
        LLM-->>UI: Analisis 3 level (Descriptive, Diagnostic, Predictive)
        UI-->>Pengguna: Tampilkan insights + ComposedChart
    else Score < threshold
        UI-->>Pengguna: Warning "Data tidak cukup untuk analisis AI"
    end
```

## Referensi Enum

### Payment Method (Metode Pembayaran)

| Nilai | Deskripsi |
| - | - |
| `cash` | Tunai |
| `card` | Kartu kredit/debit |
| `transfer` | Transfer bank |
| `ewallet` | Dompet elektronik (GoPay, OVO, Dana, dll) |
| `qris` | QRIS |
| `saldo` | Saldo akun |
| `mayar` | Mayar payment gateway |
| `debt` | Hutang / tempo |
| `manual_transfer` | Transfer manual |
| `midtrans` | Midtrans gateway |
| `tripay` | Tripay gateway |
| `stripe` | Stripe gateway |
| `paypal` | PayPal |

### Payment Status (Status Pembayaran)

| Nilai | Deskripsi |
| - | - |
| `pending` | Menunggu pembayaran |
| `pending_verification` | Menunggu verifikasi pembayaran |
| `partially_paid` | Baru dibayar sebagian |
| `paid` | Lunas |
| `failed` | Pembayaran gagal |
| `refunded` | Dana dikembalikan |
| `rejected` | Pembayaran ditolak |

### Order Status (Status Pesanan)

| Nilai | Deskripsi |
| - | - |
| `pending` | Pesanan baru diterima |
| `processing` | Sedang diproses |
| `shipped` | Sedang dikirim |
| `delivered` | Sampai di tujuan |
| `completed` | Selesai |
| `cancelled` | Dibatalkan |
| `rejected` | Ditolak |

### Sales Channel (Channel Penjualan)

| Nilai | Deskripsi |
| - | - |
| `offline_pos` | Transaksi POS langsung |
| `offline` | Penjualan offline lainnya |
| `website` | Website e-commerce |
| `online_catalog` | Katalog online |
| `marketplace` | Marketplace (Shopee, Tokopedia, dll) |
| `landing_page` | Landing page |
| `whatsapp` | Order via WhatsApp |
| `reseller` | Reseller |
| `b2b` | Business-to-Business |
| `grab` | GrabFood |
| `social_media` | Media sosial |

### Financial Record Type (Jenis Transaksi Keuangan)

| Nilai | Deskripsi |
| - | - |
| `income` | Pemasukan |
| `expense` | Pengeluaran |
| `transfer` | Transfer antar akun |

### Financial Record Source (Sumber Pencatatan)

| Nilai | Deskripsi |
| - | - |
| `manual` | Input manual |
| `ai_text` | Dari AI text input |
| `ai_scan` | Dari AI scan struk |
| `pos` | Dari transaksi POS |
| `manufacturing` | Dari modul manufaktur |
| `distribution` | Dari modul distribusi |
| `recall` | Dari batch recall |
| `stock_opname` | Dari stock opname |

### Report Type (Jenis Laporan Snapshot)

| Nilai | Deskripsi |
| - | - |
| `profit_loss` | Laporan laba rugi |
| `balance_sheet` | Neraca |
| `cash_flow` | Arus kas |
| `budget_vs_actual` | Anggaran vs realisasi |
| `trial_balance` | Neraca saldo |
| `custom` | Laporan kustom |

### Report Template Type (Tipe Template Laporan)

| Nilai | Deskripsi |
| - | - |
| `financial` | Laporan keuangan |
| `sales` | Laporan penjualan |
| `inventory` | Laporan inventaris |
| `hr` | Laporan SDM |
| `project` | Laporan proyek |
| `custom` | Template kustom |

### Member Role (Role Anggota)

| Nilai | Deskripsi |
| - | - |
| `owner` | Pemilik perusahaan |
| `admin` | Administrator |
| `supervisor` | Supervisor |
| `store_admin` | Admin toko |
| `stock_admin` | Admin stok |
| `finance_admin` | Admin keuangan |
| `hr_admin` | Admin SDM |
| `transaction_admin` | Admin transaksi |
| `employee` | Karyawan |
| `production_operator` | Operator produksi |
| `qc_inspector` | Inspector QC |
| `sales_marketing` | Sales & Marketing |
| `partner_distributor` | Partner/Distributor |

### Attendance Status (Status Absensi)

| Nilai | Deskripsi |
| - | - |
| `present` | Hadir tepat waktu |
| `late` | Hadir terlambat |
| `absent` | Tidak hadir |
| `sick` | Sakit |
| `leave` | Cuti |
| `wfh` | Work from home |

### Leave Type (Jenis Cuti)

| Nilai | Deskripsi |
| - | - |
| `annual` | Cuti tahunan |
| `sick` | Cuti sakit |
| `unpaid` | Cuti tanpa gaji |
| `maternity` | Cuti melahirkan |
| `paternity` | Cuti ayah |
| `emergency` | Cuti darurat |

### Quality Check Status (Status QC)

| Nilai | Deskripsi |
| - | - |
| `pending` | Menunggu inspeksi |
| `approved` | Disetujui — masuk inventory |
| `rejected` | Ditolak — tidak masuk inventory |
| `conditional` | Disetujui dengan catatan |

### Checklist Result (Hasil Checklist QC)

| Nilai | Deskripsi |
| - | - |
| `pass` | Lulus standar |
| `fail` | Tidak lulus |
| `warning` | Peringatan |
| `na` | Tidak berlaku |

### Project Status (Status Proyek)

| Nilai | Deskripsi |
| - | - |
| `planning` | Perencanaan |
| `in_progress` | Sedang berjalan |
| `on_hold` | Ditunda |
| `completed` | Selesai |
| `cancelled` | Dibatalkan |

### Asset Condition (Kondisi Aset)

| Nilai | Deskripsi |
| - | - |
| `excellent` | Sangat baik |
| `good` | Baik |
| `fair` | Cukup |
| `poor` | Buruk |

### Product Type (Tipe Produk)

| Nilai | Deskripsi |
| - | - |
| `finished_good` | Produk jadi |
| `raw_material` | Bahan baku |
| `semi_finished` | Produk setengah jadi |
| `packaging_material` | Bahan kemasan |
| `bundle` | Paket bundle virtual |

## Kontrol Akses Berbasis Role (RBAC)

Berikut matriks hak akses untuk fitur Company Reports berdasarkan role anggota perusahaan:

| Role | Lihat Laporan | Export Laporan | Lihat Finance | Lihat HR | Lihat QC | Kelola Template | Simpan Snapshot |
| - | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| `owner` | Ya | Ya | Ya | Ya | Ya | Ya | Ya |
| `admin` | Ya | Ya | Ya | Ya | Ya | Ya | Ya |
| `supervisor` | Ya | Ya | Ya | Ya | Ya | Tidak | Tidak |
| `store_admin` | Ya | Ya | Tidak | Terbatas | Tidak | Tidak | Tidak |
| `stock_admin` | Terbatas | Ya | Tidak | Tidak | Ya | Tidak | Tidak |
| `finance_admin` | Ya | Ya | Ya | Terbatas | Tidak | Ya | Ya |
| `hr_admin` | Ya | Ya | Tidak | Ya | Tidak | Ya | Tidak |
| `transaction_admin` | Ya | Ya | Tidak | Tidak | Tidak | Tidak | Tidak |
| `employee` | Terbatas | Tidak | Tidak | Tidak | Tidak | Tidak | Tidak |
| `production_operator` | Tidak | Tidak | Tidak | Tidak | Terbatas | Tidak | Tidak |
| `qc_inspector` | Terbatas | Tidak | Tidak | Tidak | Ya | Tidak | Tidak |
| `sales_marketing` | Ya | Ya | Tidak | Tidak | Tidak | Tidak | Tidak |
| `partner_distributor` | Terbatas | Tidak | Tidak | Tidak | Tidak | Tidak | Tidak |

**Catatan:**

* **Ya** = Akses penuh untuk modul tersebut
* **Terbatas** = Hanya dapat melihat data yang relevan dengan tanggung jawabnya
* **Tidak** = Tidak memiliki akses
* Hak akses detail dikonfigurasi per-member melalui field `permissions` pada entitas `CompanyMember` (contoh: `can_view_reports`, `can_view_finance`, `can_view_hr`, `can_view_inventory`)
* Permission `can_view_reports` harus bernilai `true` agar anggota dapat mengakses tab laporan


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