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

# Order management

<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: "Order Management"
description: "Manajemen order multi-channel terpusat — OrderManagement.jsx (614 baris), ProductOrder + MarketplaceOrder, batch processing, WhatsApp notification, dan timeline tracking."
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

# Order Management

<img src="https://mintcdn.com/quinnofspicy/ny1xnfpEa_OBdv6T/docs/mintlify/screenshots/pos/order-management.png?fit=max&auto=format&n=ny1xnfpEa_OBdv6T&q=85&s=41ca6ae941e9a33f2f2a92e9e20a9424" alt="Order Management" width="1920" height="1080" data-path="docs/mintlify/screenshots/pos/order-management.png" />

**Order Management** (`OrderManagement.jsx` — 614 baris) adalah halaman terpusat untuk mengelola semua pesanan yang masuk dari berbagai channel penjualan. Halaman ini menggabungkan data dari **dua entitas order** — `ProductOrder` (pesanan internal dari website/WhatsApp) dan `MarketplaceOrder` (pesanan dari Shopee, Tokopedia, dll) — ke dalam satu tampilan tabel yang bisa di-filter, di-search, dan di-batch update.

Dengan Order Management, kamu bisa melacak status setiap pesanan dari **awal masuk hingga selesai dikirim** ke pelanggan, tanpa perlu berpindah platform. Setiap perubahan status bisa memicu **notifikasi WhatsApp otomatis** ke pelanggan.

## Arsitektur Komponen

```mermaid theme={null}
graph TB
    subgraph "OrderManagement.jsx — 614 lines"
        direction TB
        FILTER[Filter Bar<br/>Status + Channel + Date + Outlet]
        SEARCH[Search Bar<br/>Invoice / Customer / Order ID]
        TABLE[Order Table<br/>Paginated + Sortable]
        DETAIL[Order Detail Modal<br/>Items + Timeline + Actions]
        BATCH[Batch Actions Bar<br/>Multi-select + Status Update]
        METRICS[Metrics Cards<br/>Total + Revenue + Completion Rate]
    end

    subgraph "Data Sources"
        PO[ProductOrder<br/>Internal orders<br/>from /toko]
        MO[MarketplaceOrder<br/>External orders<br/>from marketplaces]
    end

    subgraph "Actions"
        STATUS[Status Transition<br/>6 states]
        NOTIFY[WhatsApp Notification<br/>Auto-send on change]
        PRINT[Print Invoice<br/>PDF generator]
    end

    PO & MO --> FILTER
    FILTER --> SEARCH
    SEARCH --> TABLE
    TABLE --> DETAIL & BATCH
    DETAIL --> STATUS & NOTIFY & PRINT
    BATCH --> STATUS
```

## Dual-Entity Order Model

| Aspek | ProductOrder | MarketplaceOrder |
| - | - | - |
| **Sumber** | Website `/toko`, WhatsApp, manual input | Shopee, Tokopedia, Lazada |
| **Payment** | Upload bukti bayar manual | Auto-confirmed by marketplace |
| **Fulfillment** | Admin proses sendiri | Admin proses + input tracking |
| **Status** | 6 states (lihat di bawah) | 4 states (menunggu → dikirim → selesai) |
| **Fields** | 20+ fields | 15+ fields |
| **Notification** | WhatsApp auto-send | Marketplace API sync |
| **Cancellation** | Admin atau customer | Marketplace-dependent |

## Alur Order Multi-Channel

```mermaid theme={null}
flowchart LR
    subgraph "Sumber Order"
        S1[Kasir POS]
        S2[Toko Online /toko]
        S3[Marketplace<br/>Shopee/Tokopedia]
        S4[WhatsApp]
        S5[B2B / Reseller]
    end

    subgraph "Order Management"
        OM1[Unified Table<br/>614 lines]
        OM2[Status Tracking<br/>6 states]
        OM3[Batch Processing<br/>Multi-select]
    end

    subgraph "Output"
        O1[Processing]
        O2[Shipping]
        O3[Completed]
    end

    S1 & S2 & S3 & S4 & S5 --> OM1
    OM1 --> OM2 --> OM3
    OM3 --> O1 --> O2 --> O3
```

## Fitur Utama

| Fitur | Deskripsi | Implementasi |
| - | - | - |
| **Unified View** | Semua order dari seluruh channel dalam satu tabel | Merge ProductOrder + MarketplaceOrder |
| **Multi-Filter** | Filter berdasarkan status, channel, tanggal, outlet | Client-side filtering |
| **Status Update** | Update status pesanan secara langsung | Server function `updateOrderStatus` |
| **Detail Lengkap** | Item, alamat, info pelanggan, catatan khusus | Modal detail dengan tabs |
| **Timeline Tracking** | Tracking pesanan dengan timeline visual | Status history array |
| **Search** | Pencarian berdasarkan invoice, nama, atau ID | Debounced text search |
| **Batch Update** | Centang beberapa order → ubah status bersamaan | Multi-select + bulk API call |
| **WhatsApp Notification** | Notifikasi otomatis ke pelanggan saat status berubah | WhatsApp gateway integration |
| **Metrics Cards** | Total order, revenue, completion rate, avg processing time | Real-time aggregation |

## Status Order & Timeline

```mermaid theme={null}
stateDiagram-v2
    [*] --> MenungguPembayaran: Order dibuat
    MenungguPembayaran --> Diverifikasi: Upload bukti bayar / auto-confirm
    MenungguPembayaran --> Dibatalkan: Timeout / customer cancel
    Diverifikasi --> Diproses: Admin konfirmasi & mulai siapkan
    Diproses --> Dikirim: Barang diserahkan ke kurir + tracking number
    Dikirim --> Selesai: Customer konfirmasi terima
    Dibatalkan --> [*]
    Selesai --> [*]
```

| Status | Ikon | Deskripsi | Notifikasi | Aksi |
| - | - | - | - | - |
| **Menunggu Pembayaran** | ⏳ | Order dibuat, belum dibayar | Reminder ke customer | Konfirmasi bayar, Batalkan |
| **Diverifikasi** | ✅ | Pembayaran sudah diverifikasi | Konfirmasi ke customer | Mulai proses |
| **Diproses** | 📦 | Sedang dikemas/disiapkan | Update status | Input tracking, Kirim |
| **Dikirim** | 🚚 | Barang dalam pengiriman | Tracking number | Tandai selesai |
| **Selesai** | ✔️ | Pesanan diterima customer | Request review | — |
| **Dibatalkan** | ❌ | Order dibatalkan | Konfirmasi pembatalan | — |

## Cara Akses

| Metode | Detail |
| - | - |
| **URL** | `/companypos` (tab Order Management) |
| **Sidebar** | Menu **POS** → **Order Management** |

## Flow Penggunaan

```mermaid theme={null}
flowchart TD
    A[Buka Order Management] --> B[Lihat semua order dalam tabel]
    B --> C[Gunakan filter untuk menyaring]
    C --> D{Cari order tertentu?}
    D -->|Ya| E[Gunakan search bar]
    D -->|Tidak| F[Klik order untuk detail]
    E --> F
    F --> G[Update status sesuai tahap]
    G --> H{Banyak order?}
    H -->|Ya| I[Gunakan batch update]
    H -->|Tidak| J[Update satu per satu]
    I --> K[Status terupdate]
    J --> K
    K --> L{WhatsApp notification?}
    L -->|Ya| M[Auto-send ke customer]
    L -->|Tidak| N[Skip]
```

## Filter & Pencarian

| Filter | Opsi | Deskripsi |
| - | - | - |
| **Status** | Menunggu Pembayaran, Diverifikasi, Diproses, Dikirim, Selesai, Dibatalkan | Filter per status |
| **Channel** | Offline, Marketplace, Website, WhatsApp, Reseller, B2B, Grab, Social Media | Filter per sumber |
| **Tanggal** | Hari ini, Kemarin, 7 hari terakhir, 30 hari terakhir, Custom range | Date range picker |
| **Outlet** | Semua outlet, atau pilih outlet spesifik | Filter per lokasi |
| **Customer** | Cari berdasarkan nama atau nomor telepon | Text search |

## Order dari Website

```mermaid theme={null}
sequenceDiagram
    participant C as Customer
    participant W as Website /toko
    participant OM as Order Management
    participant A as Admin

    C->>W: Checkout produk
    W->>OM: ProductOrder created (Status: Menunggu Pembayaran)
    C->>W: Upload bukti bayar
    W->>OM: Status → Diverifikasi
    A->>OM: Verifikasi pembayaran ✓
    OM->>OM: Status → Diproses
    A->>OM: Input tracking number + proses & kirim
    OM->>OM: Status → Dikirim
    OM-->>C: WhatsApp: "Pesanan Anda sedang dalam perjalanan"
    C-->>OM: Konfirmasi terima
    OM->>OM: Status → Selesai
```

## Order dari WhatsApp

| Langkah | Aksi | Status | Notifikasi |
| - | - | - | - |
| 1 | Customer chat WhatsApp | — | — |
| 2 | CS input order manual ke sistem | Menunggu Pembayaran | Auto-reply: "Order diterima" |
| 3 | Customer kirim bukti bayar | Diverifikasi | — |
| 4 | Admin verifikasi pembayaran | Diproses | WhatsApp: "Pembayaran dikonfirmasi" |
| 5 | Admin proses & input tracking | Dikirim | WhatsApp: "Pesanan dikirim + resi" |
| 6 | Customer konfirmasi terima | Selesai | WhatsApp: "Terima kasih!" |

## Batch Processing

```mermaid theme={null}
flowchart LR
    A[Centang multiple orders] --> B[Pilih aksi batch]
    B --> C{Aksi}
    C -->|Update Status| D[Semua order → status baru]
    C -->|Print Invoice| E[Generate PDF semua order]
    C -->|Send Notification| F[WhatsApp blast ke semua customer]
    D --> G[Success/Failure report per order]
    E --> G
    F --> G
```

## Metrik Order

| Metrik | Deskripsi | Sumber |
| - | - | - |
| **Total Order** | Jumlah total order dalam periode | `COUNT(*)` |
| **Total Revenue** | Total pendapatan dari semua order | `SUM(total_amount)` |
| **Average Order Value** | Rata-rata nilai per order | `AVG(total_amount)` |
| **Completion Rate** | Persentase order yang selesai | `completed / total × 100` |
| **Avg Processing Time** | Rata-rata waktu dari order masuk hingga kirim | `AVG(shipped_at - created_at)` |
| **Pending Count** | Jumlah order yang belum diproses | `WHERE status IN ('menunggu', 'diverifikasi')` |

## Tips

* **Cek halaman ini secara berkala** sepanjang hari agar tidak ada pesanan yang terlewat atau terlambat diproses
* **Manfaatkan filter channel** untuk menganalisis dari mana sebagian besar pesanan berasal dan fokus pada channel paling produktif
* **Gunakan batch update** saat volume tinggi — centang semua order yang sudah dikemas lalu ubah status ke "Dikirim" sekaligus
* **Perhatikan timeline** setiap order untuk mengidentifikasi bottleneck dalam pemrosesan
* **Set reminder** untuk order yang sudah terlalu lama di status tertentu (> 24 jam di "Diproses" perlu investigasi)
* **Monitor completion rate** — jika di bawah 90%, ada masalah di pipeline fulfillment

***

## Entity Schema — Order Management

Berikut adalah dokumentasi schema entitas yang mendasari fitur Order Management pada POS QUINNOFSPICY.

### Entity Relationship Diagram

```mermaid theme={null}
erDiagram
    CompanyPOSProduct ||--o{ CompanyPOSTransaction : "items[].product_id"
    CompanyPOSProduct ||--o{ QuinnOrder : "items[].sku"
    CompanyPOSTransaction }o--|| QuinnOrder : "pos_transaction_id"
    CompanyPOSTransaction {
        string company_id PK
        string location_id FK
        string transaction_number UK
        string invoice_number
        date_time transaction_date
        array items
        number subtotal
        number discount_amount
        number tax_amount
        number total
        string payment_method
        string payment_status
        string order_status
        string status
        string source
        string sales_channel
        string customer_id FK
        string cashier_id FK
    }
    QuinnOrder {
        string company_id PK
        string checkout_request_id UK
        string pos_transaction_id FK
        string order_number UK
        string customer_name
        string customer_phone
        string customer_email
        string shipping_address
        string city
        array items
        number subtotal
        number shipping_cost
        number total
        string payment_method
        string status
        string payment_status
        string fulfillment_status
        string reservation_status
        string sales_channel
    }
    CompanyPOSProduct {
        string company_id PK
        string name
        string sku UK
        string category
        string category_key
        string variant_key
        number price
        number cost
        number stock
        string product_type
        boolean is_active
        boolean is_bundle
        object channel_pricing
    }
```

### Tabel Schema — CompanyPOSTransaction

Entitas utama untuk setiap transaksi POS (kasir), mencakup pesanan offline maupun online yang diproses melalui sistem POS.

| Field | Tipe | Required | Default | Deskripsi |
| - | - | - | - | - |
| `company_id` | `string` | ✅ | — | ID perusahaan (multi-tenant) |
| `location_id` | `string` | — | — | ID lokasi gudang/toko |
| `location_name` | `string` | — | — | Nama lokasi transaksi |
| `transaction_number` | `string` | ✅ | — | Nomor transaksi unik (auto-generated) |
| `invoice_number` | `string` | — | — | Nomor invoice untuk cetak |
| `transaction_date` | `date-time` | — | — | Tanggal dan waktu transaksi |
| `items` | `array<Item>` | ✅ | — | Daftar produk yang dibeli |
| `subtotal` | `number` | — | — | Subtotal sebelum diskon & pajak |
| `discount_amount` | `number` | — | `0` | Nominal diskon |
| `discount_percentage` | `number` | — | `0` | Persentase diskon (0–100) |
| `tax_amount` | `number` | — | `0` | PPN (inclusive atau exclusive) |
| `total` | `number` | ✅ | — | Total akhir transaksi |
| `total_amount` | `number` | — | — | Total akhir (alias untuk `total`) |
| `payment_method` | `enum` | — | — | Metode pembayaran (lihat [Enum](#enum-payment_method)) |
| `payment_amount` | `number` | — | — | Jumlah uang yang dibayar |
| `payments` | `array<Payment>` | — | — | Detail split payment (multi-tender) |
| `payment_status` | `enum` | — | `pending` | Status pembayaran |
| `paid_amount` | `number` | — | `0` | Nominal pembayaran terverifikasi |
| `remaining_amount` | `number` | — | `0` | Sisa kekurangan tagihan |
| `excess_amount` | `number` | — | `0` | Kelebihan nominal transfer |
| `change_amount` | `number` | — | `0` | Kembalian |
| `payment_reference` | `string` | — | — | No. referensi bukti transfer/QRIS |
| `payment_verified_by` | `string` | — | — | Nama verifier pembayaran |
| `payment_verified_at` | `date-time` | — | — | Waktu verifikasi pembayaran |
| `customer_id` | `string` | — | — | ID member/pelanggan (jika ada) |
| `customer_name` | `string` | — | — | Nama pelanggan |
| `customer_phone` | `string` | — | — | Nomor telepon pelanggan |
| `customer_address` | `string` | — | — | Alamat pelanggan |
| `points_earned` | `number` | — | `0` | Poin loyalitas yang didapat |
| `points_used` | `number` | — | `0` | Poin loyalitas yang dipakai |
| `cashier_id` | `string` | — | — | ID kasir yang memproses |
| `cashier_name` | `string` | — | — | Nama kasir |
| `assigned_to_id` | `string` | — | — | ID staf yang ditugaskan |
| `assigned_to_name` | `string` | — | — | Nama staf yang ditugaskan |
| `notes` | `string` | — | — | Catatan transaksi |
| `source` | `enum` | — | `pos` | Sumber transaksi asli |
| `order_status` | `enum` | — | `pending` | Status pemrosesan order |
| `status` | `enum` | — | `completed` | Status transaksi (lifecycle penuh) |
| `tracking_number` | `string` | — | — | Nomor resi pengiriman |
| `shipping_address` | `string` | — | — | Alamat pengiriman |
| `sales_channel` | `enum` | — | `offline_pos` | Kanal penjualan ternormalisasi |
| `metadata` | `object` | — | — | Data tambahan (info online order, dll) |
| `verified_at` | `date-time` | — | — | Waktu order diverifikasi |
| `verified_by` | `string` | — | — | Akun yang memverifikasi |
| `processed_at` | `date-time` | — | — | Waktu order mulai diproses |
| `shipped_at` | `date-time` | — | — | Waktu order dikirim |
| `delivered_at` | `date-time` | — | — | Waktu order diterima |
| `cancelled_at` | `date-time` | — | — | Waktu order dibatalkan |

### Tabel Schema — QuinnOrder

Entitas order dari Quinn Storefront (website publik), terhubung ke `CompanyPOSTransaction` melalui `pos_transaction_id` untuk integrasi ERP dan laporan keuangan.

| Field | Tipe | Required | Default | Deskripsi |
| - | - | - | - | - |
| `company_id` | `string` | — | — | ID perusahaan (auto-linked dari storefront) |
| `checkout_request_id` | `string` | — | — | Idempotency key dari checkout publik |
| `pos_transaction_id` | `string` | — | — | ID `CompanyPOSTransaction` terkait (mirror ERP) |
| `order_number` | `string` | — | — | Nomor pesanan unik untuk pelanggan |
| `customer_name` | `string` | ✅ | — | Nama lengkap pelanggan |
| `customer_phone` | `string` | ✅ | — | Nomor WhatsApp pelanggan |
| `customer_email` | `string` | — | — | Email pelanggan |
| `shipping_address` | `string` | ✅ | — | Alamat lengkap pengiriman |
| `city` | `string` | — | — | Kota tujuan pengiriman |
| `notes` | `string` | — | — | Catatan tambahan dari pelanggan |
| `items` | `array<QuinnItem>` | ✅ | — | Daftar produk yang dipesan |
| `subtotal` | `number` | — | `0` | Total harga produk sebelum ongkir |
| `shipping_cost` | `number` | — | `0` | Biaya pengiriman |
| `total` | `number` | ✅ | `0` | Total akhir yang harus dibayar |
| `payment_method` | `enum` | — | `whatsapp` | Metode pembayaran pilihan pelanggan |
| `status` | `enum` | — | `pending` | Status pesanan (lifecycle utama) |
| `customer_id` | `string` | — | — | ID Customer di CRM |
| `auth_user_id` | `string` | — | — | ID akun auth pemilik pesanan |
| `sales_channel` | `string` | — | `website` | Kanal penjualan |
| `shipping_address_snapshot` | `object` | — | — | Snapshot alamat pengiriman saat order dibuat |
| `payment_proof_url` | `string` | — | — | URL gambar bukti transfer |
| `payment_proof_uploaded_at` | `string` | — | — | Waktu upload bukti pembayaran |
| `payment_status` | `enum` | — | `unpaid` | Status pembayaran terverifikasi |
| `fulfillment_status` | `enum` | — | `unprocessed` | Status pemenuhan barang fisik |
| `reservation_status` | `enum` | — | `active` | Status reservasi stok inventori |
| `paid_amount` | `number` | — | `0` | Nominal pembayaran terverifikasi sah |
| `remaining_amount` | `number` | — | `0` | Sisa tagihan belum dibayar |
| `excess_amount` | `number` | — | `0` | Kelebihan transfer untuk review kredit/refund |
| `rejection_reason` | `string` | — | — | Alasan penolakan bukti pembayaran |
| `payment_proofs` | `array<PaymentProof>` | — | — | Histori semua bukti transfer yang diunggah |
| `status_history` | `array<StatusEntry>` | — | — | Histori riwayat perubahan status |

### Sub-Schema — `items[]` (CompanyPOSTransaction)

Setiap elemen dalam array `items` pada `CompanyPOSTransaction` merepresentasikan satu baris produk yang dibeli.

| Field | Tipe | Deskripsi |
| - | - | - |
| `product_id` | `string` | ID produk di `CompanyPOSProduct` |
| `product_name` | `string` | Nama produk (snapshot saat transaksi) |
| `sku` | `string` | SKU/barcode produk |
| `quantity` | `number` | Jumlah yang dibeli |
| `price` | `number` | Harga satuan saat transaksi |
| `discount` | `number` | Diskon per-baris (default: 0) |
| `subtotal` | `number` | Subtotal baris (qty × price − discount) |
| `unit` | `string` | Satuan produk (pcs, gram, dll) |
| `unit_cost` | `number` | HPP per satuan (untuk kalkulasi laba) |
| `total_cost` | `number` | Total HPP (unit\_cost × quantity) |
| `note` | `string` | Catatan per-baris dari kasir (opsional) |

### Sub-Schema — `items[]` (QuinnOrder)

Setiap elemen dalam array `items` pada `QuinnOrder` merepresentasikan satu produk yang dipesan melalui storefront.

| Field | Tipe | Deskripsi |
| - | - | - |
| `sku` | `string` | SKU produk |
| `name` | `string` | Nama produk |
| `size` | `string` | Ukuran/variant yang dipilih |
| `price` | `number` | Harga satuan |
| `quantity` | `number` | Jumlah yang dipesan |
| `subtotal` | `number` | Subtotal baris (price × quantity) |

### Sub-Schema — `payments[]` (Split Payment)

| Field | Tipe | Deskripsi |
| - | - | - |
| `method` | `string` | Metode pembayaran (cash, card, transfer, dll) |
| `amount` | `number` | Nominal yang dibayar via metode ini |
| `change_amount` | `number` | Kembalian untuk metode ini (default: 0) |
| `account_id` | `string` | ID akun kas/bank tujuan |
| `reference` | `string` | Nomor referensi transfer |
| `verified_by` | `string` | Akun yang memverifikasi |
| `verified_at` | `date-time` | Waktu verifikasi |

### Sub-Schema — `payment_proofs[]` (QuinnOrder)

| Field | Tipe | Deskripsi |
| - | - | - |
| `id` | `string` | ID unik bukti transfer |
| `proof_url` | `string` | URL gambar bukti transfer |
| `claimed_amount` | `number` | Nominal yang diklaim pelanggan |
| `transfer_date` | `string` | Tanggal transfer |
| `destination_bank` | `string` | Bank tujuan transfer |
| `notes` | `string` | Catatan tambahan |
| `uploaded_at` | `string` | Waktu upload |
| `status` | `enum` | Status verifikasi (`pending`, `accepted`, `rejected`) |
| `verified_at` | `string` | Waktu verifikasi |
| `verified_by` | `string` | Akun verifier |
| `bank_reference` | `string` | Referensi bank |
| `rejection_reason` | `string` | Alasan penolakan (jika `rejected`) |

### Sub-Schema — `status_history[]` (QuinnOrder)

| Field | Tipe | Deskripsi |
| - | - | - |
| `status` | `string` | Status baru yang dimasuki |
| `timestamp` | `string` | Waktu perubahan status |
| `actor` | `string` | Akun yang mengubah status |
| `notes` | `string` | Catatan perubahan (opsional) |

***

## State Machine — Order Status Lifecycle

### CompanyPOSTransaction — `order_status`

```mermaid theme={null}
stateDiagram-v2
    [*] --> pending: Order dibuat (kasir/online)
    pending --> processing: Admin konfirmasi & mulai siapkan
    processing --> shipped: Barang diserahkan ke kurir
    shipped --> delivered: Customer konfirmasi terima
    delivered --> completed: Fulfillment selesai
    pending --> cancelled: Timeout / customer cancel
    processing --> cancelled: Admin batalkan
    processing --> rejected: Pembayaran ditolak
    cancelled --> [*]
    completed --> [*]
    rejected --> [*]
```

### QuinnOrder — `status`

```mermaid theme={null}
stateDiagram-v2
    [*] --> pending: Checkout dari storefront
    pending --> confirmed: Pembayaran diverifikasi
    confirmed --> processing: Admin mulai siapkan barang
    processing --> shipped: Barang dikirim + resi
    shipped --> completed: Customer terima barang
    pending --> cancelled: Customer cancel / timeout
    confirmed --> cancelled: Admin batalkan
    completed --> [*]
    cancelled --> [*]
```

### QuinnOrder — `fulfillment_status`

```mermaid theme={null}
stateDiagram-v2
    [*] --> unprocessed: Order masuk
    unprocessed --> processing: Admin mulai siapkan
    processing --> ready: Barang siap ambil/kirim
    ready --> shipped: Diserahkan ke kurir
    shipped --> delivered: Diterima pelanggan
    delivered --> returned: Retur diterima
    returned --> [*]
    delivered --> [*]
```

### QuinnOrder — `payment_status`

```mermaid theme={null}
stateDiagram-v2
    [*] --> unpaid: Order dibuat
    unpaid --> pending_verification: Upload bukti transfer
    pending_verification --> paid: Verifikasi diterima
    pending_verification --> rejected: Bukti ditolak
    rejected --> pending_verification: Upload bukti baru
    unpaid --> partially_paid: Pembayaran sebagian
    partially_paid --> paid: Pelunasan diverifikasi
    paid --> refunded: Refund diproses
    paid --> [*]
    refunded --> [*]
```

### QuinnOrder — `reservation_status`

```mermaid theme={null}
stateDiagram-v2
    [*] --> active: Stok direservasi saat checkout
    active --> consumed: Order diproses, stok terpakai
    active --> released: Order dibatalkan, stok dikembalikan
    active --> expired: Timeout pembayaran, stok dilepas
    consumed --> [*]
    released --> [*]
    expired --> [*]
```

***

## Sequence Diagrams

### 1. Pembuatan Order dari POS (Kasir)

```mermaid theme={null}
sequenceDiagram
    participant Kasir as Kasir (POS UI)
    participant API as Backend API
    participant TXN as CompanyPOSTransaction
    participant INV as CompanyPOSInventory
    participant PROD as CompanyPOSProduct

    Kasir->>API: POST /api/pos/transactions (items, payment)
    API->>PROD: Validasi harga & stok per produk
    PROD-->>API: OK — harga & stok valid
    API->>TXN: Insert transaksi (status: completed, payment_status: paid)
    TXN-->>API: transaction_id + transaction_number
    API->>INV: Kurangi stok per lokasi (atomic decrement)
    INV-->>API: Stok terupdate
    API-->>Kasir: 200 OK — { transaction_number, receipt_data }
    Kasir->>Kasir: Cetak struk / tampilkan konfirmasi
```

### 2. Pembuatan Order dari Quinn Storefront

```mermaid theme={null}
sequenceDiagram
    participant Cust as Pelanggan (Website)
    participant SF as Quinn Storefront
    participant API as Backend API
    participant ORD as QuinnOrder
    participant TXN as CompanyPOSTransaction
    participant INV as CompanyPOSInventory

    Cust->>SF: Checkout (items, alamat, pembayaran)
    SF->>API: POST /api/quinn/checkout
    API->>ORD: Insert QuinnOrder (status: pending, reservation: active)
    API->>INV: Reservasi stok (reservation_status: active)
    INV-->>API: Stok ter-reservasi
    API->>TXN: Mirror ke CompanyPOSTransaction (pos_transaction_id)
    TXN-->>API: transaction_id
    API->>ORD: Update pos_transaction_id
    API-->>SF: 200 OK — { order_number, checkout_request_id }
    SF-->>Cust: Halaman konfirmasi + instruksi pembayaran
    Note over Cust: Upload bukti transfer via WhatsApp / website
    Cust->>API: POST /api/quinn/orders/:id/payment-proof
    API->>ORD: Update payment_status → pending_verification
    API-->>Cust: Bukti diterima, menunggu verifikasi
```

### 3. Kitchen Display — Order Masuk Dapur

```mermaid theme={null}
sequenceDiagram
    participant Kasir as Kasir (POS)
    participant API as Backend API
    participant TXN as CompanyPOSTransaction
    participant KDS as Kitchen Display
    participant Kitchen as Staf Dapur

    Kasir->>API: POST /api/pos/transactions (order_status: pending)
    API->>TXN: Insert transaksi (order_status: pending)
    TXN-->>API: transaction_id
    API->>KDS: Push event — order baru masuk
    KDS->>Kitchen: Tampilkan order di layar dapur (antrian)
    Kitchen->>KDS: Klik "Mulai Siapkan"
    KDS->>API: PATCH /api/pos/transactions/:id (order_status: processing)
    API->>TXN: Update order_status → processing, processed_at = now()
    Kitchen->>KDS: Klik "Siap Saji"
    KDS->>API: PATCH /api/pos/transactions/:id (order_status: ready)
    KDS->>Kasir: Notifikasi — order siap diantar ke pelanggan
    Kasir->>KDS: Klik "Served"
    KDS->>API: PATCH /api/pos/transactions/:id (order_status: completed)
    API->>TXN: Update order_status → completed
```

### 4. Modifikasi Order (Update Status & Verifikasi Pembayaran)

```mermaid theme={null}
sequenceDiagram
    participant Admin as Admin / Verifikator
    participant API as Backend API
    participant ORD as QuinnOrder
    participant TXN as CompanyPOSTransaction
    participant WA as WhatsApp Gateway
    participant Cust as Pelanggan

    Admin->>API: GET /api/quinn/orders/:id (lihat detail + bukti transfer)
    API-->>Admin: Detail order + payment_proofs[]
    Admin->>API: PATCH /api/quinn/orders/:id (payment_status: paid, status: confirmed)
    API->>ORD: Update payment_status → paid, paid_amount, status → confirmed
    API->>TXN: Sync payment_status → paid pada pos_transaction_id
    API->>WA: Kirim notifikasi ke pelanggan
    WA->>Cust: "Pembayaran Anda telah dikonfirmasi. Pesanan sedang diproses."
    Note over Admin: Lanjut ke fulfillment
    Admin->>API: PATCH /api/quinn/orders/:id (fulfillment_status: processing → shipped)
    API->>ORD: Update fulfillment_status → shipped, tracking_number
    API->>WA: Kirim notifikasi resi
    WA->>Cust: "Pesanan Anda sedang dalam perjalanan. No. Resi: XXX"
    Cust->>API: Konfirmasi terima barang
    API->>ORD: status → completed, fulfillment_status → delivered, reservation_status → consumed
    API->>TXN: Sync status → completed
```

***

## Enum Tables

### `order_status` (CompanyPOSTransaction)

Status pemrosesan order pada `CompanyPOSTransaction`. Mengontrol alur kerja dari order masuk hingga selesai.

| Nilai | Deskripsi | Transisi Selanjutnya |
| - | - | - |
| `pending` | Order baru dibuat, belum diproses | `processing`, `cancelled` |
| `processing` | Sedang disiapkan/dikemas | `shipped`, `cancelled`, `rejected` |
| `shipped` | Barang diserahkan ke kurir | `delivered` |
| `delivered` | Barang diterima pelanggan | `completed` |
| `completed` | Order selesai (final) | — |
| `cancelled` | Order dibatalkan (final) | — |
| `rejected` | Order ditolak (mis. pembayaran gagal) (final) | — |

### `status` (CompanyPOSTransaction)

Status transaksi penuh (termasuk refund) pada `CompanyPOSTransaction`.

| Nilai | Deskripsi |
| - | - |
| `pending` | Transaksi menunggu konfirmasi |
| `processing` | Transaksi sedang diproses |
| `shipped` | Barang sedang dikirim |
| `delivered` | Barang sudah diterima |
| `completed` | Transaksi selesai (final) |
| `failed` | Transaksi gagal |
| `refunded` | Dana dikembalikan ke pelanggan |
| `cancelled` | Transaksi dibatalkan |

### `status` (QuinnOrder)

Status pesanan pada `QuinnOrder` (lifecycle utama dari checkout hingga selesai).

| Nilai | Deskripsi | Transisi Selanjutnya |
| - | - | - |
| `pending` | Order baru masuk dari storefront | `confirmed`, `cancelled` |
| `confirmed` | Pembayaran diverifikasi | `processing`, `cancelled` |
| `processing` | Sedang disiapkan | `shipped` |
| `shipped` | Dalam pengiriman | `completed` |
| `completed` | Selesai (final) | — |
| `cancelled` | Dibatalkan (final) | — |

### `payment_method` (CompanyPOSTransaction)

| Nilai | Deskripsi |
| - | - |
| `cash` | Tunai (kasir) |
| `card` | Kartu debit/kredit |
| `transfer` | Transfer bank manual |
| `ewallet` | E-wallet (GoPay, OVO, Dana, dll) |
| `qris` | QRIS (scan QR pembayaran) |
| `saldo` | Saldo member/loyalty |
| `mayar` | Mayar payment gateway |
| `debt` | Hutang/piutang (tempo) |
| `manual_transfer` | Transfer manual (verifikasi manual) |
| `midtrans` | Midtrans payment gateway |
| `tripay` | Tripay payment gateway |
| `stripe` | Stripe payment gateway |
| `paypal` | PayPal |

### `payment_method` (QuinnOrder)

| Nilai | Deskripsi |
| - | - |
| `transfer_bank` | Transfer bank (upload bukti) |
| `cod` | Bayar di tempat (Cash on Delivery) |
| `whatsapp` | Konfirmasi & bayar via WhatsApp |

### `payment_status` (CompanyPOSTransaction)

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

### `payment_status` (QuinnOrder)

| Nilai | Deskripsi |
| - | - |
| `unpaid` | Belum ada pembayaran |
| `pending_verification` | Bukti transfer diunggah, menunggu verifikasi |
| `partially_paid` | Pembayaran sebagian terverifikasi |
| `paid` | Pembayaran lunas terverifikasi |
| `rejected` | Bukti transfer ditolak |
| `refunded` | Dana dikembalikan |

### `fulfillment_status` (QuinnOrder)

| Nilai | Deskripsi |
| - | - |
| `unprocessed` | Belum diproses |
| `processing` | Sedang disiapkan |
| `ready` | Siap dikirim/diambil |
| `shipped` | Dalam pengiriman |
| `delivered` | Diterima pelanggan |
| `returned` | Barang diretur |

### `reservation_status` (QuinnOrder)

| Nilai | Deskripsi |
| - | - |
| `active` | Stok sedang direservasi untuk order ini |
| `consumed` | Stok sudah terpakai (order diproses) |
| `released` | Stok dikembalikan (order dibatalkan) |
| `expired` | Stok dilepas otomatis karena timeout |

### `source` (CompanyPOSTransaction)

| Nilai | Deskripsi |
| - | - |
| `pos` | Transaksi kasir langsung |
| `online_catalog` | Katalog online |
| `website` | Website perusahaan |
| `marketplace` | Marketplace (Shopee, Tokopedia, dll) |
| `landing_page` | Landing page kampanye |
| `whatsapp` | Order via WhatsApp |
| `reseller` | Order dari reseller |
| `b2b` | Order B2B (business-to-business) |
| `grab` | Order via GrabFood |
| `social_media` | Order dari media sosial |

### `sales_channel` (CompanyPOSTransaction & QuinnOrder)

Kanal penjualan ternormalisasi. Field `source` pada `CompanyPOSTransaction` dipertahankan untuk kompatibilitas legacy.

| Nilai | Deskripsi |
| - | - |
| `offline_pos` | POS offline (kasir langsung) — default POS |
| `offline` | Offline (legacy, setara `offline_pos`) |
| `website` | Website perusahaan |
| `online_catalog` | Katalog online |
| `marketplace` | Marketplace eksternal |
| `landing_page` | Landing page kampanye |
| `whatsapp` | WhatsApp |
| `reseller` | Reseller |
| `b2b` | B2B |
| `grab` | GrabFood |
| `social_media` | Media sosial |

***

## RBAC — Hak Akses Order Management

Berikut adalah matriks hak akses berdasarkan peran (role) terhadap operasi pada entitas `CompanyPOSTransaction` dan `QuinnOrder`.

| Operasi | Role | Kondisi | Deskripsi |
| - | - | - | - |
| **Create** | `admin` | — | Admin dapat membuat transaksi/order tanpa batasan |
| **Create** | `member` | `data.company_id == user.active_company_id` | Member hanya bisa membuat order dalam perusahaan aktifnya |
| **Create** | `member` | `created_by_id == user.id` | Member bisa membuat order atas namanya sendiri |
| **Read** | `admin` | — | Admin dapat membaca semua transaksi/order |
| **Read** | `member` | `data.company_id == user.active_company_id` | Member hanya bisa membaca order dalam perusahaan aktifnya |
| **Read** | `member` | `created_by_id == user.id` | Member bisa membaca order yang dibuatnya sendiri |
| **Update** | `admin` | — | Admin dapat mengubah semua transaksi/order |
| **Update** | `member` | `data.company_id == user.active_company_id` | Member hanya bisa mengubah order dalam perusahaan aktifnya |
| **Update** | `member` | `created_by_id == user.id` | Member bisa mengubah order yang dibuatnya sendiri |
| **Delete** | `admin` | — | Admin dapat menghapus semua transaksi/order |
| **Delete** | `member` | `data.company_id == user.active_company_id` | Member hanya bisa menghapus order dalam perusahaan aktifnya |
| **Delete** | `member` | `created_by_id == user.id` | Member bisa menghapus order yang dibuatnya sendiri |

<Info>
  **Catatan RBAC:** Semua aturan RLS (Row-Level Security) menggunakan pola `$or` dengan tiga kondisi: (1) kecocokan `company_id` dengan `active_company_id` user, (2) kecocokan `created_by_id` dengan `user.id`, atau (3) role `admin`. Ini memastikan isolasi data multi-tenant yang ketat sambil tetap mengizinkan admin akses penuh.
</Info>

<Warning>
  **Penting:** Field `company_id` divalidasi agar tidak boleh `null` atau string kosong (`""`) pada semua operasi CRUD. Ini mencegah data orphan yang tidak terikat ke perusahaan manapun.
</Warning>


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