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

<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 Products"
description: "Katalog produk perusahaan dengan variant, pricing, barcode, kategorisasi, dan import massal."
-----------------------------------------------------------------------------------------------------------

# Company Products

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

Company Products adalah fondasi dari seluruh modul inventori dan penjualan. Semua produk yang dijual di POS, toko online, maupun channel B2B berasal dari katalog ini. Di sini kamu mengelola data produk lengkap — gambar, deskripsi, spesifikasi, variant (ukuran, warna, rasa), harga per variant, barcode, dan kategorisasi. Produk yang di-create di level perusahaan kemudian bisa ditampilkan di Company Store dan di-assign ke outlet mana saja.

## Arsitektur Company Products

```mermaid theme={null}
graph TB
    subgraph "Katalog Produk"
        PC[Product Catalog<br/>Data Dasar Produk]
        VR[Variants<br/>Ukuran, Warna, Rasa]
        PR[Pricing<br/>Harga per Variant]
        BC[Barcode<br/>Generate & Print]
        CT[Categories<br/>Kategorisasi]
        IMG[Images<br/>Foto Produk]
    end

    subgraph "Operasi"
        IMP[Import Massal<br/>Excel/CSV]
        EXP[Export<br/>CSV/Excel/PDF]
        TOG[Toggle Aktif/Nonaktif<br/>Kontrol Ketersediaan]
    end

    subgraph "Output ke Modul Lain"
        POS[POS<br/>Produk di Kasir]
        STR[Company Store<br/>Etalase Toko]
        MFG[Manufacturing<br/>BOM & Produksi]
        INV[Inventory<br/>Stok Tracking]
    end

    PC --> VR --> PR
    PC --> BC & CT & IMG
    IMP --> PC
    PC --> POS & STR & MFG & INV
    TOG --> POS & STR
```

## Data Produk — Field Lengkap

### Informasi Dasar

| Field | Tipe | Wajib | Deskripsi |
| - | - | - | - |
| **Nama Produk** | Text | Ya | Nama produk (contoh: Ayam Suwir Petir) |
| **SKU** | Auto/Manual | Ya | Stock Keeping Unit (QOS-{kat}-{seq}) |
| **Kategori** | Dropdown | Ya | Sambal & Bumbu, Keripik, Minuman, dll |
| **Deskripsi** | Rich text | Tidak | Deskripsi detail produk |
| **Gambar** | Upload (multi) | Tidak | Foto produk (max 5 gambar) |
| **Berat** | Number | Tidak | Berat per unit (gram) |
| **Dimensi** | L x W x H | Tidak | Ukuran kemasan (cm) |
| **Status** | Toggle | Ya | Aktif (bisa dijual) / Nonaktif |

### Spesifikasi (Opsional)

| Field | Deskripsi |
| - | - |
| **Komposisi** | Daftar bahan |
| **Nilai Gizi** | Informasi nutrisi |
| **Allergen** | Peringatan alergen |
| **Sertifikasi** | Halal, BPOM, P-IRT |
| **Shelf Life** | Masa simpan (hari) |
| **Storage** | Kondisi penyimpanan (suhu ruang, dingin, beku) |

## Manajemen Variant

Variant memungkinkan satu produk memiliki beberapa pilihan:

```mermaid theme={null}
graph TD
    P[Produk: Ayam Suwir Petir] --> V1[Variant: 150g]
    P --> V2[Variant: 300g]
    P --> V3[Variant: 500g]
    V1 --> S1[SKU: QOS-ASP-150<br/>Harga: Rp 25.000<br/>Barcode: QOS-ASP-150]
    V2 --> S2[SKU: QOS-ASP-300<br/>Harga: Rp 45.000<br/>Barcode: QOS-ASP-300]
    V3 --> S3[SKU: QOS-ASP-500<br/>Harga: Rp 70.000<br/>Barcode: QOS-ASP-500]
```

### Kombinasi Variant

Sistem mendukung kombinasi multi-dimensi:

| Produk | Dimensi | Variant yang Dihasilkan |
| - | - | - |
| Ayam Suwir Petir | Ukuran (3) | 3 variant |
| Kaos Quinn | Ukuran (4) x Warna (3) | 12 variant |
| Sambal Matah | Ukuran (2) x Tipe (2) | 4 variant |

### Field per Variant

| Field | Deskripsi |
| - | - |
| **Nama Variant** | Contoh: "150g", "Merah - M" |
| **SKU** | Unique per variant |
| **Harga** | Bisa berbeda per variant |
| **Stok** | Terpisah per variant |
| **Barcode** | Unique per variant |
| **Berat** | Bisa berbeda per variant |
| **Status** | Aktif/nonaktif per variant |

## Pricing

### Harga per Produk/Variant

| Tipe Harga | Deskripsi | Digunakan Di |
| - | - | - |
| **Harga Jual** | Harga retail standar | POS, Company Store |
| **Harga B2B** | Harga khusus untuk pelanggan B2B | Sales Order B2B |
| **Harga Reseller** | Harga untuk reseller | Channel Reseller |
| **HPP** | Harga Pokok Produksi | Kalkulasi margin |
| **Harga Beli** | Harga dari supplier (bahan baku) | Purchase Order |

### Contoh Pricing Matrix

| Variant | HPP | Harga Jual | Harga B2B | Harga Reseller | Margin |
| - | - | - | - | - | - |
| 150g | Rp 12.000 | Rp 25.000 | Rp 20.000 | Rp 18.000 | 52% |
| 300g | Rp 22.000 | Rp 45.000 | Rp 36.000 | Rp 32.000 | 51% |
| 500g | Rp 35.000 | Rp 70.000 | Rp 56.000 | Rp 50.000 | 50% |

## Barcode per Produk

Setiap produk dan variant bisa memiliki barcode:

| Aksi | Detail |
| - | - |
| **Generate otomatis** | Berdasarkan SKU (QOS-{kat}-{seq}) |
| **Generate custom** | Input kode manual |
| **Print label** | Satuan atau batch |
| **Lihat barcode** | Klik ikon barcode di daftar produk |

## Kategorisasi

### Struktur Kategori

```mermaid theme={null}
graph TD
    ROOT[Semua Produk] --> C1[Sambal & Bumbu]
    ROOT --> C2[Keripik & Snack]
    ROOT --> C3[Minuman]
    ROOT --> C4[Bahan Baku]
    ROOT --> C5[Kemasan]
    C1 --> S1[Sambal Matang]
    C1 --> S2[Sambal Mentah]
    C1 --> S3[Bumbu Racik]
    C2 --> K1[Keripik Singkong]
    C2 --> K2[Keripik Pisang]
```

### Fungsi Kategori

| Fungsi | Detail |
| - | - |
| **Filter** | Saring produk berdasarkan kategori |
| **Report** | Laporan per kategori |
| **Pricing** | Strategi harga berbeda per kategori |
| **Stock** | Minimum stok berbeda per kategori |
| **Display** | Pengelompokan di etalase toko |

## Import Massal

### Langkah Import

```mermaid theme={null}
flowchart LR
    A[Download Template<br/>Excel/CSV] --> B[Isi Data Produk<br/>Sesuai Format]
    B --> C[Upload File]
    C --> D[Preview & Validasi]
    D --> E{Valid?}
    E -->|Ya| F[Import Berhasil]
    E -->|Tidak| G[Download Error Log<br/>Perbaiki & Upload Ulang]
```

### Template Import

| Kolom Template | Wajib | Format | Contoh |
| - | - | - | - |
| **Nama Produk** | Ya | Text | Ayam Suwir Petir |
| **Kategori** | Ya | Text | Sambal & Bumbu |
| **SKU** | Ya | Text | QOS-ASP-150 |
| **Harga** | Ya | Number | 25000 |
| **HPP** | Tidak | Number | 12000 |
| **Stok** | Tidak | Number | 100 |
| **Berat (gram)** | Tidak | Number | 150 |
| **Deskripsi** | Tidak | Text | Ayam suwir pedas... |
| **Barcode** | Tidak | Text | Auto-generate jika kosong |

### Validasi Import

| Check | Error jika Gagal |
| - | - |
| SKU unik | "SKU sudah digunakan" |
| Kategori valid | "Kategori tidak ditemukan" |
| Harga numerik | "Format harga tidak valid" |
| Nama tidak kosong | "Nama produk wajib diisi" |

## Export

| Format | Konten | Kapan Digunakan |
| - | - | - |
| **CSV** | Data produk + stok | Import ke sistem lain |
| **Excel** | Data produk + stok + valuasi | Laporan ke manajemen |
| **PDF** | Katalog produk dengan gambar | Brosur, katalog cetak |

## Tampilan: Tabel vs Grid

| Mode | Tampilan | Cocok Untuk |
| - | - | - |
| **Tabel** | Kolom data lengkap, sorting, filtering | Manajemen data, editing |
| **Grid** | Card dengan gambar produk | Preview katalog, visual review |

## Toggle Aktif/Nonaktif

| Status | Efek |
| - | - |
| **Aktif** | Muncul di POS, Company Store, bisa dijual |
| **Nonaktif** | Tidak muncul di POS dan Store, stok tetap tercatat |

> **Tips**: Nonaktifkan produk yang sudah tidak dijual alih-alih menghapusnya, supaya riwayat transaksi dan stok tetap terjaga.

## Tips

* **Lengkapi data produk** termasuk gambar dan deskripsi yang jelas — ini membantu saat produk ditampilkan di toko online maupun saat staf mencari produk di kasir.
* **Review katalog secara berkala** untuk menonaktifkan produk yang sudah tidak dijual atau mengupdate harga yang berubah.
* **Gunakan import massal** jika perlu menambah banyak produk sekaligus — jauh lebih cepat daripada input satu per satu.

***

## Entity Schema Reference

### Entity Relationship Diagram

```mermaid theme={null}
erDiagram
    CompanyPOSProduct ||--o{ CompanyPOSInventory : "stok tracking"
    CompanyPOSProduct }o--|| CompanyPOSCategory : "kategorisasi"
    CompanyPOSProduct ||--o{ HPPCalculation : "kalkulasi HPP"
    CompanyPOSProduct ||--o{ CompanyPOSProduct : "bundle components"
    CompanyPOSCategory ||--o{ CompanyPOSProduct : "berisi produk"
    CompanyPOSInventory }o--|| HPPCalculation : "referensi produksi"

    CompanyPOSProduct {
        string id PK
        string company_id FK
        string name "Nama produk"
        string sku "SKU/Barcode"
        string category "Kategori produk"
        string category_key "Kategori canonical"
        string category_name "Label kategori"
        string variant_key "Varian canonical"
        string variant_name "Label varian"
        string variant_label "Gabungan kategori+varian"
        number size_grams "Ukuran canonical (gram)"
        string base_product_key "Kunci produk utama"
        string description "Deskripsi produk"
        number price "Harga jual"
        number cost "Harga modal/beli"
        number stock "Stok saat ini"
        number min_stock "Minimum stok alert"
        string image_url "URL gambar utama"
        array gallery "Galeri foto (max 20)"
        array variants "Varian produk"
        boolean is_active "Status aktif"
        datetime deactivated_at "Waktu nonaktif"
        string deactivated_by "Akun penonaktif"
        number tax_rate "Persentase pajak"
        string supplier "Nama supplier"
        string unit "Satuan produk"
        string variant "Varian (rasa, dll)"
        string barcode "Barcode EAN-13"
        enum product_type "Tipe produk"
        enum packaging_type "Jenis kemasan"
        number net_weight_grams "Berat bersih (gram)"
        number gross_weight_grams "Berat kotor (gram)"
        enum storage_condition "Kondisi penyimpanan"
        boolean is_bundle "Paket bundle virtual"
        array bundle_components "Komponen bundle"
        object channel_pricing "Harga per channel"
        boolean is_locked "Data terkunci"
        datetime locked_at "Waktu penguncian"
        string locked_by "User pengunci"
        string lock_reason "Alasan penguncian"
        number sold_count "Total terjual"
    }

    CompanyPOSCategory {
        string id PK
        string company_id FK
        string name "Nama kategori"
        string description "Penjelasan kategori"
        string icon "Icon emoji"
        string color "Warna kategori"
        number order "Urutan tampil"
    }

    CompanyPOSInventory {
        string id PK
        string company_id FK
        string product_id FK
        string product_name "Nama produk"
        enum type "Tipe pergerakan"
        number quantity "Jumlah perubahan"
        number stock_before "Stok sebelum"
        number stock_after "Stok sesudah"
        string reason "Alasan pergerakan"
        string reference_id "ID transaksi terkait"
        string notes "Catatan"
        string performed_by "Pelaku"
    }

    HPPCalculation {
        string id PK
        string company_id FK
        string product_id FK
        string product_name "Nama produk"
        enum calculation_method "Metode kalkulasi"
        date period_start "Awal periode"
        date period_end "Akhir periode"
        array raw_materials "Bahan baku"
        array direct_labor_costs "Biaya tenaga kerja"
        array overhead_costs "Biaya overhead"
        number total_raw_materials "Total bahan baku"
        number total_direct_labor "Total tenaga kerja"
        number total_overhead "Total overhead"
        number total_production_cost "Total biaya produksi"
        number units_produced "Unit diproduksi"
        number hpp_per_unit "HPP per unit"
        number profit_margin_percentage "Target margin %"
        number suggested_selling_price "Harga jual saran"
        string notes "Catatan"
        string production_order_id "ID ProductionOrder"
        string production_batch_id "Batch ID produksi"
        enum cost_status "Status kelengkapan biaya"
    }
```

### Tabel Schema: CompanyPOSProduct

Entitas utama katalog produk perusahaan. Menyimpan seluruh data produk yang dijual di POS, toko online, dan channel B2B.

| # | Field | Tipe | Wajib | Default | Deskripsi |
| - | - | - | - | - | - |
| 1 | `company_id` | string | Ya | — | ID perusahaan pemilik produk |
| 2 | `name` | string | Ya | — | Nama produk (contoh: Ayam Suwir Petir) |
| 3 | `sku` | string | Tidak | — | SKU/Barcode produk (QOS-{kat}-{seq}) |
| 4 | `category` | string | Tidak | — | Kategori produk (free text) |
| 5 | `category_key` | string | Tidak | — | Kategori canonical: `kecil`, `besar`, `pouch`, `bundle`, `snack` |
| 6 | `category_name` | string | Tidak | — | Label display untuk kategori canonical |
| 7 | `variant_key` | string | Tidak | — | Varian canonical: `original`, `extra_spicy`, `bundle` |
| 8 | `variant_name` | string | Tidak | — | Label display untuk varian canonical |
| 9 | `variant_label` | string | Tidak | — | Gabungan kategori + varian untuk POS/inventory/manufacturing |
| 10 | `size_grams` | number | Tidak | — | Ukuran canonical produk dalam gram |
| 11 | `base_product_key` | string | Tidak | — | Kunci produk utama sebelum pemecahan kategori/varian |
| 12 | `description` | string | Tidak | — | Deskripsi detail produk (rich text) |
| 13 | `price` | number | Ya | — | Harga jual standar (Rupiah) |
| 14 | `cost` | number | Tidak | — | Harga modal/beli dari supplier (Rupiah) |
| 15 | `stock` | number | Tidak | `0` | Stok saat ini |
| 16 | `min_stock` | number | Tidak | `5` | Minimum stok untuk trigger alert |
| 17 | `image_url` | string | Tidak | — | URL gambar utama produk |
| 18 | `gallery` | array\[string] | Tidak | — | Galeri foto produk (maks 20 foto) |
| 19 | `variants` | array\[object] | Tidak | — | Varian produk (ukuran, warna, rasa) |
| 20 | `is_active` | boolean | Tidak | `true` | Status aktif produk — jika `false`, tidak tampil di POS/Store |
| 21 | `deactivated_at` | datetime | Tidak | — | Timestamp saat SKU dinonaktifkan (audit trail) |
| 22 | `deactivated_by` | string | Tidak | — | Akun yang menonaktifkan SKU (audit trail) |
| 23 | `tax_rate` | number | Tidak | `0` | Persentase pajak (0–100) |
| 24 | `supplier` | string | Tidak | — | Nama supplier produk |
| 25 | `unit` | string | Tidak | `pcs` | Satuan produk (pcs, kg, liter, dll) |
| 26 | `variant` | string | Tidak | — | Varian produk (Pedas, Manis, Gurih, dll) |
| 27 | `barcode` | string | Tidak | — | Barcode / QR Code produk (EAN-13) |
| 28 | `product_type` | enum | Tidak | `finished_good` | Tipe produk — lihat [Enum: product\_type](#enum-product_type) |
| 29 | `packaging_type` | enum | Tidak | — | Jenis kemasan — lihat [Enum: packaging\_type](#enum-packaging_type) |
| 30 | `net_weight_grams` | number | Tidak | — | Berat bersih isi produk dalam gram |
| 31 | `gross_weight_grams` | number | Tidak | — | Berat kotor termasuk kemasan dalam gram |
| 32 | `storage_condition` | enum | Tidak | `room_temperature` | Kondisi penyimpanan — lihat [Enum: storage\_condition](#enum-storage_condition) |
| 33 | `is_bundle` | boolean | Tidak | `false` | Menandakan paket bundle virtual (BND-01) |
| 34 | `bundle_components` | array\[object] | Tidak | — | Komponen SKU penyusun paket bundle |
| 35 | `channel_pricing` | object | Tidak | — | Harga khusus per saluran penjualan (CHN-02) |
| 36 | `is_locked` | boolean | Tidak | `false` | Data terkunci karena sudah ada transaksi (DQ-01) |
| 37 | `locked_at` | datetime | Tidak | — | Timestamp penguncian data (DQ-01) |
| 38 | `locked_by` | string | Tidak | — | Email user yang mengunci data (DQ-01) |
| 39 | `lock_reason` | string | Tidak | — | Alasan penguncian / reason code perubahan harga (DQ-01) |
| 40 | `sold_count` | number | Tidak | `0` | Total jumlah produk terjual (akumulator transaksi) |

#### Sub-object: `variants[]`

| Field | Tipe | Deskripsi |
| - | - | - |
| `name` | string | Nama varian (contoh: "150g", "Merah - M") |
| `sku` | string | SKU unik per varian |
| `price` | number | Harga jual per varian |
| `stock` | number | Stok terpisah per varian |

#### Sub-object: `bundle_components[]`

| Field | Tipe | Wajib | Deskripsi |
| - | - | - | - |
| `sku` | string | Ya | SKU komponen |
| `product_id` | string | Tidak | ID produk komponen |
| `name` | string | Tidak | Nama komponen |
| `quantity` | number | Ya (default: `1`) | Jumlah satuan komponen dalam bundle |
| `unit` | string | Tidak | Satuan komponen |

#### Sub-object: `channel_pricing`

| Field | Tipe | Deskripsi |
| - | - | - |
| `offline_pos` | number | Harga untuk POS offline |
| `marketplace` | number | Harga untuk marketplace (Tokopedia, Shopee, dll) |
| `website` | number | Harga untuk website perusahaan |
| `whatsapp` | number | Harga untuk order via WhatsApp |
| `reseller` | number | Harga khusus reseller |
| `b2b` | number | Harga khusus B2B |
| `grab` | number | Harga untuk channel GrabFood |
| `social_media` | number | Harga untuk order via social media |

### Tabel Schema: CompanyPOSCategory

Kategori produk level perusahaan. Digunakan untuk mengelompokkan produk agar mudah dicari, difilter, dan dilaporkan.

| # | Field | Tipe | Wajib | Default | Deskripsi |
| - | - | - | - | - | - |
| 1 | `company_id` | string | Ya | — | ID perusahaan pemilik kategori |
| 2 | `name` | string | Ya | — | Nama kategori (contoh: Sambal & Bumbu) |
| 3 | `description` | string | Tidak | — | Penjelasan jenis produk dalam kategori (maks 1000 karakter) |
| 4 | `icon` | string | Tidak | — | Icon emoji untuk tampilan visual |
| 5 | `color` | string | Tidak | `#3b82f6` | Warna hex kategori untuk UI |
| 6 | `order` | number | Tidak | `0` | Urutan tampil kategori |

### Tabel Schema: CompanyPOSInventory

Log pergerakan stok produk. Setiap kali stok berubah (masuk, keluar, atau penyesuaian), entri baru dibuat sebagai audit trail.

| # | Field | Tipe | Wajib | Deskripsi |
| - | - | - | - | - |
| 1 | `company_id` | string | Ya | ID perusahaan |
| 2 | `product_id` | string | Ya | ID produk yang bergerak |
| 3 | `product_name` | string | Tidak | Nama produk (denormalisasi untuk query cepat) |
| 4 | `type` | enum | Ya | Tipe pergerakan: `in`, `out`, `adjustment` |
| 5 | `quantity` | number | Ya | Jumlah perubahan stok |
| 6 | `stock_before` | number | Tidak | Stok sebelum pergerakan |
| 7 | `stock_after` | number | Tidak | Stok setelah pergerakan |
| 8 | `reason` | string | Tidak | Alasan pergerakan (pembelian, penjualan, rusak, dll) |
| 9 | `reference_id` | string | Tidak | ID transaksi terkait (PO, SO, adjustment) |
| 10 | `notes` | string | Tidak | Catatan tambahan |
| 11 | `performed_by` | string | Tidak | ID user yang melakukan pergerakan |

### Tabel Schema: HPPCalculation

Kalkulasi Harga Pokok Produksi (HPP) per produk. Mendukung tiga metode: FIFO, LIFO, dan Average.

| # | Field | Tipe | Wajib | Default | Deskripsi |
| - | - | - | - | - | - |
| 1 | `company_id` | string | Tidak | — | ID perusahaan |
| 2 | `product_id` | string | Tidak | — | ID produk yang dihitung HPP-nya |
| 3 | `product_name` | string | Ya | — | Nama produk |
| 4 | `calculation_method` | enum | Tidak | `Average` | Metode kalkulasi: `FIFO`, `LIFO`, `Average` |
| 5 | `period_start` | date | Ya | — | Tanggal awal periode kalkulasi |
| 6 | `period_end` | date | Ya | — | Tanggal akhir periode kalkulasi |
| 7 | `raw_materials` | array\[object] | Tidak | — | Daftar bahan baku yang digunakan |
| 8 | `direct_labor_costs` | array\[object] | Tidak | — | Daftar biaya tenaga kerja langsung |
| 9 | `overhead_costs` | array\[object] | Tidak | — | Daftar biaya overhead (listrik, sewa, dll) |
| 10 | `total_raw_materials` | number | Tidak | — | Total biaya bahan baku (Rupiah) |
| 11 | `total_direct_labor` | number | Tidak | — | Total biaya tenaga kerja langsung (Rupiah) |
| 12 | `total_overhead` | number | Tidak | — | Total biaya overhead (Rupiah) |
| 13 | `total_production_cost` | number | Tidak | — | Total biaya produksi = bahan + tenaga + overhead |
| 14 | `units_produced` | number | Tidak | — | Jumlah unit yang diproduksi |
| 15 | `hpp_per_unit` | number | Tidak | — | HPP per unit = total\_production\_cost / units\_produced |
| 16 | `profit_margin_percentage` | number | Tidak | — | Target profit margin (%) |
| 17 | `suggested_selling_price` | number | Tidak | — | Harga jual yang disarankan berdasarkan HPP + margin |
| 18 | `notes` | string | Tidak | — | Catatan tambahan |
| 19 | `production_order_id` | string | Tidak | — | ID ProductionOrder terkait (CST-06) |
| 20 | `production_batch_id` | string | Tidak | — | Batch ID produksi terkait (CST-06) |
| 21 | `cost_status` | enum | Tidak | `complete` | Status kelengkapan biaya — lihat [Enum: cost\_status](#enum-cost_status) |

***

## State Machine: Siklus Hidup Produk

```mermaid theme={null}
stateDiagram-v2
    [*] --> Draft: Produk dibuat\n(data dasar diisi)

    Draft --> Active: Publish\n(lengkapi data wajib,\nupload gambar)

    Active --> Active: Update harga / stok\n(varian, pricing)
    Active --> Archived: Nonaktifkan\n(deactivated_at di-set)

    Archived --> Active: Aktifkan kembali\n(clear deactivated_at)
    Archived --> [*]: Hapus permanen\n(jika tidak ada transaksi)

    state Active {
        [*] --> Unlocked
        Unlocked --> Locked: Transaksi pertama tercatat\n(is_locked = true)
        Locked --> Unlocked: Admin override\n(lock_reason dicatat)
    }

    state Draft {
        note right
            Field editable: semua field
            Tidak tampil di POS/Store
            Bisa di-preview internal
        end note
    }

    state Active {
        note right
            Tampil di POS, Store, B2B
            Stok aktif tracking
            Bisa dijual
        end note
    }

    state Archived {
        note right
            Tidak tampil di POS/Store
            Stok tetap tercatat
            Riwayat transaksi terjaga
        end note
    }
```

### Aturan Transisi State

| Dari | Ke | Trigger | Efek |
| - | - | - | - |
| `[*]` | Draft | Create produk baru | `is_active = false`, data dasar tersimpan |
| Draft | Active | Publish (data lengkap) | `is_active = true`, tampil di POS/Store |
| Active | Archived | Toggle nonaktif | `deactivated_at` di-set, `is_active = false` |
| Archived | Active | Toggle aktif kembali | `deactivated_at` di-clear, `is_active = true` |
| Active (Unlocked) | Active (Locked) | Transaksi pertama tercatat | `is_locked = true`, field nama/SKU/satuan tidak bisa diedit |
| Active (Locked) | Active (Unlocked) | Admin override | `lock_reason` dicatat untuk audit |

***

## Sequence Diagrams

### 1. Pembuatan Produk Baru

```mermaid theme={null}
sequenceDiagram
    actor User as Admin/Staff
    participant UI as Frontend
    participant API as Backend API
    participant DB as Database
    participant SKU as SKU Generator

    User->>UI: Klik "Tambah Produk"
    UI->>UI: Tampilkan form produk
    User->>UI: Isi nama, kategori, harga, deskripsi
    User->>UI: Upload gambar produk (opsional)
    User->>UI: Klik "Simpan"
    UI->>API: POST /api/company-products
    API->>API: Validasi field wajib (name, price, company_id)
    API->>SKU: Generate SKU (QOS-{kat}-{seq})
    SKU-->>API: Return SKU unik
    API->>API: Set default values (stock=0, is_active=true, unit=pcs)
    API->>DB: INSERT CompanyPOSProduct
    DB-->>API: Return created product + id
    API-->>UI: Return 201 Created
    UI->>UI: Redirect ke detail produk
    UI-->>User: Tampilkan produk berhasil dibuat
```

### 2. Manajemen Variant

```mermaid theme={null}
sequenceDiagram
    actor User as Admin/Staff
    participant UI as Frontend
    participant API as Backend API
    participant DB as Database
    participant BAR as Barcode Generator

    User->>UI: Buka detail produk
    User->>UI: Klik "Tambah Variant"
    UI->>UI: Tampilkan form variant (nama, SKU, harga, stok)
    User->>UI: Isi data variant (contoh: "150g", harga 25000)
    User->>UI: Klik "Simpan Variant"
    UI->>API: PATCH /api/company-products/:id/variants
    API->>API: Validasi SKU variant unik
    API->>BAR: Generate barcode untuk variant
    BAR-->>API: Return barcode (EAN-13)
    API->>DB: UPDATE variants[] pada CompanyPOSProduct
    DB-->>API: Return updated product
    API-->>UI: Return 200 OK + updated variants
    UI-->>User: Tampilkan variant baru di daftar
```

### 3. Update Harga Produk

```mermaid theme={null}
sequenceDiagram
    actor User as Admin/Staff
    participant UI as Frontend
    participant API as Backend API
    participant LOCK as Lock Checker
    participant DB as Database
    participant HPP as HPP Calculator
    participant CHN as Channel Pricing

    User->>UI: Edit harga produk
    User->>UI: Input harga baru
    User->>UI: Klik "Simpan"
    UI->>API: PATCH /api/company-products/:id {price: baru}
    API->>LOCK: Cek is_locked
    alt Produk terkunci (is_locked = true)
        LOCK-->>API: Locked
        API->>API: Cek lock_reason untuk price override
        alt Override diizinkan
            API->>API: Catat reason code (audit)
        else Override ditolak
            API-->>UI: Return 403 "Produk terkunci, hubungi admin"
        end
    end
    API->>HPP: Hitung ulang margin (hpp_per_unit vs price baru)
    HPP-->>API: Return margin percentage
    API->>CHN: Update channel_pricing (jika ada markup per channel)
    CHN-->>API: Return updated channel prices
    API->>DB: UPDATE price, channel_pricing pada CompanyPOSProduct
    DB-->>API: Return updated product
    API-->>UI: Return 200 OK + new price + margin info
    UI-->>User: Tampilkan harga baru + margin warning jika < 30%
```

***

## Enum Tables

<h3 id="enum-product_type">
  Enum: `product_type`
</h3>

Tipe produk fisik atau paket virtual. Digunakan untuk membedakan produk jadi, bahan baku, dan bundle.

| Nilai | Label | Deskripsi |
| - | - | - |
| `finished_good` | Produk Jadi | Produk siap jual ke konsumen akhir |
| `raw_material` | Bahan Baku | Material untuk produksi (cabai, bawang, dll) |
| `semi_finished` | Setengah Jadi | Produk antara yang perlu proses lanjutan |
| `packaging_material` | Material Kemasan | Kemasan, label, segel, dll |
| `bundle` | Paket Bundle | Paket virtual gabungan beberapa SKU (BND-01) |

<h3 id="enum-packaging_type">
  Enum: `packaging_type`
</h3>

Jenis kemasan fisik produk. Mempengaruhi perhitungan berat kotor dan kondisi penyimpanan.

| Nilai | Label | Deskripsi |
| - | - | - |
| `jar_glass` | Toples Kaca | Kemasan kaca (selai, sambal premium) |
| `pouch_zipper` | Pouch Zipper | Pouch dengan zip lock (bisa dibuka-tutup) |
| `pouch_sealed` | Pouch Sealed | Pouch segel permanen (sekali buka) |
| `toples_plastic` | Toples Plastik | Kemasan plastik (economis) |
| `bottle_plastic` | Botol Plastik | Botol untuk cairan/saus |
| `bulk` | Curah/Bulk | Kemasan besar tanpa retail packaging |
| `other` | Lainnya | Jenis kemasan di luar daftar di atas |

<h3 id="enum-storage_condition">
  Enum: `storage_condition`
</h3>

Kondisi penyimpanan yang diperlukan produk. Mempengaruhi penempatan gudang dan logistik.

| Nilai | Label | Suhu | Deskripsi |
| - | - | - | - |
| `room_temperature` | Suhu Ruang | 25–30°C | Produk kering, tidak perlu pendingin |
| `chilled` | Dingin | 2–8°C | Produk segar, perlu kulkas/chiller |
| `frozen` | Beku | -18°C atau lebih rendah | Produk beku, perlu freezer |

<h3 id="enum-inventory_type">
  Enum: `type` (CompanyPOSInventory)
</h3>

Tipe pergerakan stok dalam log inventori.

| Nilai | Label | Deskripsi |
| - | - | - |
| `in` | Stok Masuk | Penambahan stok (purchase order, produksi, retur) |
| `out` | Stok Keluar | Pengurangan stok (penjualan POS, sales order, waste) |
| `adjustment` | Penyesuaian | Koreksi stok (stock opname, kerusakan, selisih) |

<h3 id="enum-calculation_method">
  Enum: `calculation_method` (HPPCalculation)
</h3>

Metode kalkulasi Harga Pokok Produksi.

| Nilai | Label | Deskripsi |
| - | - | - |
| `FIFO` | First In First Out | Bahan pertama masuk dihitung pertama keluar |
| `LIFO` | Last In First Out | Bahan terakhir masuk dihitung pertama keluar |
| `Average` | Rata-rata Tertimbang | Rata-rata biaya dari semua batch bahan baku |

<h3 id="enum-cost_status">
  Enum: `cost_status` (HPPCalculation)
</h3>

Status kelengkapan data biaya dalam kalkulasi HPP (CST-05).

| Nilai | Label | Deskripsi |
| - | - | - |
| `complete` | Lengkap | Semua komponen biaya (bahan, tenaga, overhead) terisi |
| `provisional_incomplete` | Sementara (Belum Lengkap) | Ada komponen biaya yang belum terisi — HPP bersifat estimasi |
| `zero_output_pending` | Nol Output (Pending) | Belum ada unit diproduksi — HPP belum bisa dihitung |

***

## RBAC: Hak Akses Company Products

| Aksi | Super Admin | Admin | Manager | Staff | Viewer |
| - | :-: | :-: | :-: | :-: | :-: |
| Lihat daftar produk | ✅ | ✅ | ✅ | ✅ | ✅ |
| Lihat detail produk | ✅ | ✅ | ✅ | ✅ | ✅ |
| Buat produk baru | ✅ | ✅ | ✅ | ✅ | ❌ |
| Edit data produk | ✅ | ✅ | ✅ | ✅ | ❌ |
| Hapus produk | ✅ | ✅ | ❌ | ❌ | ❌ |
| Toggle aktif/nonaktif | ✅ | ✅ | ✅ | ✅ | ❌ |
| Update harga | ✅ | ✅ | ✅ | ❌ | ❌ |
| Update harga saat locked (override) | ✅ | ✅ | ❌ | ❌ | ❌ |
| Tambah/hapus variant | ✅ | ✅ | ✅ | ✅ | ❌ |
| Generate barcode | ✅ | ✅ | ✅ | ✅ | ❌ |
| Print label barcode | ✅ | ✅ | ✅ | ✅ | ✅ |
| Import massal (Excel/CSV) | ✅ | ✅ | ✅ | ❌ | ❌ |
| Export produk (CSV/Excel/PDF) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Kelola kategori | ✅ | ✅ | ✅ | ❌ | ❌ |
| Kelola channel pricing | ✅ | ✅ | ❌ | ❌ | ❌ |
| Kelola bundle components | ✅ | ✅ | ✅ | ❌ | ❌ |
| Lihat HPP & margin | ✅ | ✅ | ✅ | ❌ | ❌ |
| Lihat log inventori | ✅ | ✅ | ✅ | ✅ | ✅ |
| Adjustment stok | ✅ | ✅ | ✅ | ❌ | ❌ |


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