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

# My orders

<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: "My Orders"
description: "Halaman personal untuk tracking status pesanan, riwayat pembelian, dan aksi cepat seperti bayar ulang atau pesan kembali — menggabungkan ProductOrder dan MarketplaceOrder dalam satu timeline."
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

# My Orders

<img src="https://mintcdn.com/quinnofspicy/e4f_upKhVWcjsUmM/docs/mintlify/screenshots/pos/my-orders.png?fit=max&auto=format&n=e4f_upKhVWcjsUmM&q=85&s=eaaf41047259adc7a6a42a988d712927" alt="My Orders" width="1920" height="1080" data-path="docs/mintlify/screenshots/pos/my-orders.png" />

**My Orders** adalah halaman personal yang menampilkan semua pesanan yang dibuat oleh user yang sedang login. Halaman ini menggabungkan data dari **dua entitas terpisah** — `ProductOrder` (pesanan internal) dan `MarketplaceOrder` (pesanan dari marketplace) — ke dalam satu tampilan terpadu dengan **tracking status real-time** dan **timeline visual**.

Komponen `MyOrders.jsx` (344 baris) menggunakan polling 10 detik untuk memastikan status pesanan selalu terkini tanpa membebani server dengan request berlebihan.

## Arsitektur Data

```mermaid theme={null}
graph TB
    subgraph "Data Sources"
        PO[ProductOrder<br/>Pesanan Internal<br/>via /toko]
        MO[MarketplaceOrder<br/>Pesanan Marketplace<br/>Shopee/Tokopedia]
    end

    subgraph "MyOrders.jsx — 344 lines"
        FETCH[Data Fetching<br/>10s Polling Interval]
        MERGE[Data Merger<br/>Unified Timeline]
        FILTER[Status Filter<br/>5 States]
        RENDER[Card Renderer<br/>Timeline Visual]
    end

    subgraph "User Actions"
        PAY[Bayar Ulang]
        TRACK[Lacak Status]
        REORDER[Pesan Lagi]
        CANCEL[Batalkan]
    end

    PO --> FETCH
    MO --> FETCH
    FETCH --> MERGE --> FILTER --> RENDER
    RENDER --> PAY & TRACK & REORDER & CANCEL
```

## Dual-Entity Data Model

| Aspek | ProductOrder | MarketplaceOrder |
| - | - | - |
| **Sumber** | Website `/toko` direct checkout | Shopee, Tokopedia, dll |
| **Payment Proof** | Upload manual oleh customer | Auto-confirmed by marketplace |
| **Tracking Number** | Input manual oleh admin | Sync dari marketplace API |
| **Status Flow** | Unpaid → Verifying → Paid → Processing → Shipped → Completed | Menunggu → Dikirim → Selesai |
| **Cancellation** | Admin atau customer | Marketplace-dependent |
| **Fields** | 20+ fields termasuk `payment_proof_url`, `tracking_number` | 15+ fields termasuk `marketplace_order_id`, `platform` |

## Fitur Utama

| Fitur | Deskripsi |
| - | - |
| **Unified View** | Gabungan ProductOrder + MarketplaceOrder dalam satu list |
| **Status Tracking** | Tracking real-time dengan timeline visual per order |
| **Detail Order** | Item, jumlah, harga, total pembayaran, alamat pengiriman |
| **Riwayat** | Riwayat pesanan lengkap yang bisa ditelusuri |
| **Filter Status** | Filter: menunggu pembayaran, diproses, dikirim, selesai, dibatalkan |
| **Aksi Cepat** | Bayar ulang, batalkan pesanan, atau pesan lagi |
| **Auto-Refresh** | Polling 10 detik untuk update status real-time |
| **Notifikasi** | Alert jika ada perubahan status pada pesanan |

## Cara Akses

| Metode | Detail |
| - | - |
| **URL** | `/pos/my-orders` |
| **Sidebar** | Menu **POS** → **My Orders** |
| **Dashboard** | Widget "Pesanan Saya" di Home |

## Status & Timeline

```mermaid theme={null}
gantt
    title Timeline Order
    dateFormat HH:mm
    section Status
    Order Dibuat     :done, 00:00, 5min
    Pembayaran       :done, 00:05, 10min
    Verifikasi       :done, 00:15, 5min
    Proses & Kirim   :active, 00:20, 30min
    Selesai          :00:50, 0min
```

| Status | Warna | Deskripsi | Aksi Tersedia |
| - | - | - | - |
| **Menunggu Pembayaran** | Abu-abu | Order dibuat, belum dibayar | Bayar, Batalkan |
| **Diproses** | Biru | Sedang dikemas/disiapkan | Lacak Status |
| **Dikirim** | Kuning | Dalam perjalanan + tracking number | Lacak Kiriman |
| **Selesai** | Hijau | Diterima oleh pelanggan | Pesan Lagi, Review |
| **Dibatalkan** | Merah | Order dibatalkan | — |

## Flow Penggunaan

```mermaid theme={null}
flowchart TD
    A[Buka My Orders] --> B[Lihat pesanan aktif]
    B --> C[Klik pesanan untuk detail]
    C --> D{Status pesanan?}
    D -->|Menunggu bayar| E[Klik Bayar untuk lanjutkan]
    D -->|Diproses| F[Lihat timeline status]
    D -->|Selesai| G{Mau pesan lagi?}
    G -->|Ya| H[Klik Pesan Lagi]
    G -->|Tidak| I[Lihat riwayat]
    H --> J[Item masuk cart]
```

## Polling & Data Refresh Strategy

```mermaid theme={null}
sequenceDiagram
    participant C as MyOrders.jsx
    participant S as Server
    participant DB as Database

    loop Every 10 seconds
        C->>S: fetchOrders(userId)
        S->>DB: SELECT FROM ProductOrder + MarketplaceOrder
        DB-->>S: Return orders
        S-->>C: Merged order list
        C->>C: Diff & re-render changed items
    end

    Note over C: Cleanup on unmount:<br/>clearInterval(pollingRef)
```

| Parameter | Nilai | Alasan |
| - | - | - |
| **Interval** | 10 detik | Balance antara real-time dan server load |
| **Scope** | User-scoped | Hanya order milik user yang login (RLS) |
| **Cleanup** | `useEffect` return | Mencegah memory leak saat navigasi |
| **Error Handling** | Silent retry | Tidak ganggu user jika server timeout |

## Order Card Components

Setiap order ditampilkan dalam card yang berisi:

| Elemen | Deskripsi |
| - | - |
| **Order ID** | Nomor invoice unik (format: `INV-YYYYMMDD-XXXX`) |
| **Channel Badge** | Badge warna berdasarkan sumber order (Website/Marketplace/WhatsApp) |
| **Status Badge** | Badge warna sesuai status (lihat tabel di atas) |
| **Item Summary** | Nama produk + quantity, dipotong jika > 3 item |
| **Total** | Total pembayaran dalam format Rupiah |
| **Timestamp** | Waktu order dibuat (format relatif: "2 jam yang lalu") |
| **Action Buttons** | Kontekstual sesuai status (Bayar/Lacak/Pesan Lagi) |

## Entity Relationship Diagram

Berikut adalah diagram relasi antar entitas yang terlibat dalam halaman My Orders. Diagram ini menggambarkan bagaimana data order, produk, customer, voucher, dan inventory saling terhubung dalam ekosistem SNISHOP ERP.

```mermaid theme={null}
erDiagram
    User ||--o{ ProductOrder : "membuat (customer_id)"
    User ||--o{ MarketplaceOrder : "membuat (customer_id)"
    User ||--o{ MarketplaceCart : "memiliki (user_id)"

    POSProduct ||--o{ ProductOrder : "dipesan (product_id)"
    POSProduct ||--o{ MarketplaceCart : "ditambahkan (product_id)"
    POSProduct ||--o{ POSInventory : "pergerakan stok (product_id)"
    POSProduct }o--o| POSCategory : "dikategorikan (category)"
    POSProduct }o--o| DigitalProduct : "sinkronisasi (digital_product_id)"

    MarketplaceOrder ||--|{ MarketplaceOrderItems : "berisi (items[])"
    MarketplaceOrderItems }o--|| POSProduct : "merujuk (product_id)"

    Company ||--o{ MarketplaceOrder : "menerima (company_id)"
    Company ||--o{ CompanyPOSInventory : "mencatat (company_id)"
    Company ||--o{ CompanyPOSCategory : "mengelola (company_id)"
    Company ||--o{ CompanyPOSSettings : "konfigurasi (company_id)"
    Company ||--o{ Discount : "membuat (company_id)"

    Voucher ||--o{ ProductOrder : "digunakan (voucher_code)"
    ProductVoucher ||--o{ POSProduct : "berlaku untuk (applicable_products[])"

    POSMember ||--o{ ProductOrder : "mendapat diskon (membership)"
    ShopSettings ||--o{ POSProduct : "pengaturan toko (reseller_discounts)"

    MarketplaceOrderItems {
        string product_id
        string product_name
        number quantity
        number price
        number subtotal
    }
```

### Entitas Inti yang Terlibat

| Entitas | Peran dalam My Orders | Sumber Data |
| - | - | - |
| **ProductOrder** | Pesanan internal dari website `/toko` | Tabel `product_orders` |
| **MarketplaceOrder** | Pesanan dari channel marketplace (Shopee/Tokopedia) | Tabel `marketplace_orders` |
| **POSProduct** | Katalog produk yang dipesan | Tabel `pos_products` |
| **MarketplaceCart** | Keranjang belanja sebelum checkout | Tabel `marketplace_carts` |
| **POSInventory** | Log pergerakan stok akibat order | Tabel `pos_inventories` |
| **CompanyPOSInventory** | Log inventory per-company (multi-tenant) | Tabel `company_pos_inventories` |
| **Voucher / ProductVoucher** | Kode diskon yang diterapkan pada order | Tabel `vouchers` / `product_vouchers` |
| **POSMember** | Membership customer (tier, poin, diskon) | Tabel `pos_members` |
| **Discount** | Promo/diskon aktif dari company | Tabel `discounts` |
| **CompanyPOSSettings** | Konfigurasi POS per-company (struk, pajak) | Tabel `company_pos_settings` |
| **ShopSettings** | Pengaturan toko online (banner, reseller discount) | Tabel `shop_settings` |

***

## Entity Schema — ProductOrder

Entitas `ProductOrder` merepresentasikan pesanan internal yang dibuat melalui website `/toko`. Entitas ini memiliki 35+ field yang mencakup informasi produk, customer, pembayaran, diskon, komisi, quota, dan administrasi admin.

### Field Utama — Produk & Customer

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `product_id` | `string` | **Ya** | ID produk POS yang dipesan |
| `product_name` | `string` | **Ya** | Nama produk saat order dibuat (snapshot, bukan live reference) |
| `product_category` | `string` | Tidak | Kategori produk (disimpan saat order) |
| `product_price` | `number` | **Ya** | Harga satuan produk saat order (tidak berubah jika harga produk diubah kemudian) |
| `product_commission_rate` | `number` | Tidak | Komisi produk saat order dibuat (default: 0) |
| `selected_variant` | `object` | Tidak | Varian yang dipilih (ukuran, rasa, dll) — struktur dinamis |
| `customer_id` | `string` | **Ya** | ID user/customer yang memesan |
| `customer_email` | `string` | **Ya** | Email customer (untuk notifikasi & login) |
| `customer_name` | `string` | Tidak | Nama lengkap customer |

### Field Keuangan & Diskon

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `subtotal` | `number` | Tidak | Total harga sebelum diskon |
| `final_price` | `number` | Tidak | Harga final setelah semua diskon diterapkan |
| `used_balance` | `number` | Tidak | Saldo akun yang digunakan untuk membayar (default: 0) |
| `used_commission` | `number` | Tidak | Komisi reseller yang digunakan sebagai potongan (default: 0) |
| `reseller_discount` | `number` | Tidak | Persentase diskon reseller berdasarkan tier membership (default: 0) |
| `reseller_discount_amount` | `number` | Tidak | Nominal diskon reseller dalam rupiah (default: 0) |
| `voucher_code` | `string` | Tidak | Kode voucher yang digunakan pada order ini |
| `voucher_code_used` | `string` | Tidak | Kode voucher yang terekam (field redundan untuk tracking) |
| `voucher_discount_amount` | `number` | Tidak | Nominal potongan dari voucher (default: 0) |
| `tip_amount` | `number` | Tidak | Tip sukarela dari customer (default: 0) |

### Field Status & Administrasi

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `status` | `enum` | Tidak | Status order: `pending`, `processing`, `completed`, `cancelled` (default: `pending`) |
| `description` | `string` | Tidak | Catatan/instruksi khusus dari customer (maks. 1000 karakter) |
| `admin_notes` | `string` | Tidak | Catatan internal admin mengenai order ini |
| `result_files` | `array<string>` | Tidak | File hasil/attachment terkait order (bukti foto, dll) |
| `completed_at` | `datetime` | Tidak | Timestamp kapan order diselesaikan |
| `processed_by_admin` | `string` | Tidak | Email admin yang memproses order |
| `assigned_to_admin` | `string` | Tidak | Email admin yang mengambil/menangani order |
| `assigned_at` | `datetime` | Tidak | Timestamp kapan order diambil oleh admin |

### Field Komisi & Quota Admin

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `admin_commission_amount` | `number` | Tidak | Nominal komisi untuk admin yang memproses (default: 0) |
| `admin_commission_paid` | `boolean` | Tidak | Status apakah komisi admin sudah dibayarkan (default: `false`) |
| `quota_total` | `number` | Tidak | Total quota yang tersedia untuk produk ini (default: 0) |
| `quota_used` | `number` | Tidak | Quota yang sudah terpakai (default: 0) |
| `quota_remaining` | `number` | Tidak | Sisa quota yang masih tersedia (default: 0) |
| `is_quota_based` | `boolean` | Tidak | Apakah produk ini menggunakan sistem quota (default: `false`) |
| `parent_order_id` | `string` | Tidak | ID order induk (untuk order yang merupakan pecahan/reorder) |

***

## Entity Schema — MarketplaceOrder

Entitas `MarketplaceOrder` merepresentasikan pesanan yang masuk melalui channel marketplace eksternal atau checkout terintegrasi. Berbeda dengan `ProductOrder`, entitas ini mendukung **multi-item** dalam satu order dan memiliki field pengiriman yang lebih lengkap.

### Field Identitas & Relasi

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `order_number` | `string` | Tidak | Nomor order unik (format: `INV-YYYYMMDD-XXXX`) |
| `customer_id` | `string` | **Ya** | ID user yang membeli |
| `customer_email` | `string` | Tidak | Email customer |
| `customer_name` | `string` | Tidak | Nama customer |
| `company_id` | `string` | **Ya** | ID company/penjual yang menerima order |
| `company_name` | `string` | Tidak | Nama company (snapshot saat order) |

### Field Items (Multi-Item)

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `items` | `array<object>` | **Ya** | Daftar produk yang dipesan |
| `items[].product_id` | `string` | — | ID produk |
| `items[].product_name` | `string` | — | Nama produk |
| `items[].quantity` | `number` | — | Jumlah yang dipesan |
| `items[].price` | `number` | — | Harga satuan saat order |
| `items[].subtotal` | `number` | — | Subtotal per item (quantity × price) |

### Field Keuangan & Komisi

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `total_amount` | `number` | **Ya** | Total pembayaran seluruh item |
| `commission_rate` | `number` | Tidak | Persentase komisi marketplace (0-100) |
| `commission_amount` | `number` | Tidak | Nominal komisi dalam rupiah |
| `company_amount` | `number` | Tidak | Jumlah yang diterima company setelah potongan komisi |

### Field Status & Pengiriman

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `status` | `enum` | Tidak | Status: `pending`, `processing`, `shipped`, `delivered`, `cancelled` (default: `pending`) |
| `payment_status` | `enum` | Tidak | Status bayar: `pending`, `paid`, `refunded` (default: `paid`) |
| `shipping_address` | `object` | Tidak | Alamat pengiriman lengkap (lihat sub-field di bawah) |
| `shipping_address.name` | `string` | — | Nama penerima |
| `shipping_address.phone` | `string` | — | Nomor telepon penerima |
| `shipping_address.address` | `string` | — | Alamat lengkap |
| `shipping_address.city` | `string` | — | Kota |
| `shipping_address.province` | `string` | — | Provinsi |
| `shipping_address.postal_code` | `string` | — | Kode pos |
| `notes` | `string` | Tidak | Catatan customer untuk order ini |
| `tracking_number` | `string` | Tidak | Nomor resi pengiriman (diinput admin atau sync dari marketplace) |

### Field Timestamp Lifecycle

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `processed_at` | `datetime` | Tidak | Timestamp kapan order mulai diproses |
| `shipped_at` | `datetime` | Tidak | Timestamp kapan order dikirim |
| `delivered_at` | `datetime` | Tidak | Timestamp kapan order diterima customer |

***

## Entity Schema — Entitas Pendukung

### POSProduct (Katalog Produk)

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `name` | `string` | **Ya** | Nama produk |
| `sku` | `string` | Tidak | SKU/Barcode produk |
| `category` | `string` | Tidak | Kategori produk |
| `description` | `string` | Tidak | Deskripsi detail produk |
| `price` | `number` | **Ya** | Harga jual |
| `cost` | `number` | Tidak | Harga modal/beli (untuk kalkulasi HPP) |
| `stock` | `number` | Tidak | Stok saat ini (default: 0) |
| `min_stock` | `number` | Tidak | Minimum stok untuk alert rendah (default: 5) |
| `image_url` | `string` | Tidak | URL gambar produk |
| `variants` | `array<object>` | Tidak | Daftar varian (name, sku, price, stock) |
| `is_active` | `boolean` | Tidak | Status aktif produk (default: `true`) |
| `tax_rate` | `number` | Tidak | Persentase pajak 0-100 (default: 0) |
| `supplier` | `string` | Tidak | Nama supplier |
| `unit` | `string` | Tidak | Satuan produk (default: `pcs`) |
| `digital_product_id` | `string` | Tidak | ID dari DigitalProduct jika sinkronisasi |
| `is_synced_from_digital` | `boolean` | Tidak | Flag apakah disinkronkan dari DigitalProduct (default: `false`) |
| `last_synced` | `datetime` | Tidak | Waktu terakhir sinkronisasi |

### POSMember (Membership & Loyalty)

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `name` | `string` | **Ya** | Nama member |
| `phone` | `string` | **Ya** | Nomor telepon |
| `email` | `string` | Tidak | Email member |
| `address` | `string` | Tidak | Alamat |
| `birth_date` | `date` | Tidak | Tanggal lahir |
| `membership_tier` | `enum` | Tidak | Tier: `regular`, `silver`, `gold`, `platinum` (default: `regular`) |
| `points` | `number` | Tidak | Total poin saat ini (default: 0) |
| `lifetime_points` | `number` | Tidak | Total poin sepanjang waktu (default: 0) |
| `stamps` | `number` | Tidak | Total stamp loyalty (default: 0) |
| `has_negative_points` | `boolean` | Tidak | Flag saldo poin negatif akibat void/pembatalan (default: `false`) |
| `loyalty_deficit_points` | `number` | Tidak | Defisit poin loyalty setelah retur/void (default: 0) |
| `loyalty_review_notes` | `string` | Tidak | Catatan review penanganan deficit |
| `total_spent` | `number` | Tidak | Total akumulasi belanja (default: 0) |
| `visit_count` | `number` | Tidak | Jumlah kunjungan/transaksi (default: 0) |
| `last_visit` | `datetime` | Tidak | Waktu kunjungan terakhir |
| `discount_percentage` | `number` | Tidak | Diskon khusus member (default: 0) |
| `is_active` | `boolean` | Tidak | Status keaktifan member (default: `true`) |

### Voucher & ProductVoucher (Sistem Diskon)

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `code` | `string` | **Ya** | Kode voucher unik |
| `name` | `string` | **Ya** | Nama voucher |
| `description` | `string` | Tidak | Penjelasan syarat & ketentuan voucher (maks. 1000 karakter) |
| `discount_type` | `enum` | **Ya** | Jenis potongan: `percentage` atau `fixed_amount` |
| `discount_value` | `number` | **Ya** | Nilai potongan (% atau nominal rupiah) |
| `min_purchase` | `number` | Tidak | Minimum pembelian untuk berlaku (default: 0) |
| `max_discount` | `number` | Tidak | Maksimum potongan untuk tipe persentase |
| `usage_limit` | `number` | Tidak | Batas total penggunaan (null = unlimited) |
| `usage_count` | `number` | Tidak | Jumlah sudah digunakan (default: 0) |
| `valid_from` | `datetime` | **Ya** | Tanggal mulai aktif |
| `valid_until` | `datetime` | **Ya** | Tanggal berakhir |
| `is_active` | `boolean` | Tidak | Status aktif voucher (default: `true`) |

### MarketplaceCart (Keranjang Belanja)

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `user_id` | `string` | **Ya** | ID user pemilik keranjang |
| `company_id` | `string` | **Ya** | ID company tempat produk dijual |
| `product_id` | `string` | **Ya** | ID produk yang dimasukkan |
| `product_name` | `string` | Tidak | Nama produk |
| `product_price` | `number` | Tidak | Harga produk saat dimasukkan |
| `product_image` | `string` | Tidak | URL gambar produk |
| `description` | `string` | Tidak | Catatan buyer untuk item ini (maks. 1000 karakter) |
| `quantity` | `number` | **Ya** | Jumlah item di keranjang (default: 1) |
| `subtotal` | `number` | Tidak | Subtotal (quantity × price) |

***

## State Machine — Siklus Hidup Status Order

### ProductOrder State Machine

```mermaid theme={null}
stateDiagram-v2
    [*] --> pending : Order dibuat via checkout

    pending --> processing : Admin verifikasi pembayaran
    pending --> cancelled : Customer batalkan / timeout pembayaran

    processing --> completed : Admin tandai selesai
    processing --> cancelled : Admin batalkan (stok habis, dll)

    completed --> [*]
    cancelled --> [*]

    state pending {
        [*] --> Menunggu_Verifikasi
        Menunggu_Verifikasi --> Upload_Bukti : Customer upload bukti bayar
        Upload_Bukti --> Menunggu_Verifikasi : Menunggu admin review
    }

    state processing {
        [*] --> Dikemas
        Dikemas --> Siap_Kirim : Packing selesai
        Siap_Kirim --> Input_Resi : Admin input tracking number
    }

    state completed {
        [*] --> Dalam_Pengiriman
        Dalam_Pengiriman --> Diterima : Customer konfirmasi terima
    }
```

### MarketplaceOrder State Machine

```mermaid theme={null}
stateDiagram-v2
    [*] --> pending : Order masuk dari marketplace

    pending --> processing : Pembayaran dikonfirmasi
    pending --> cancelled : Order dibatalkan marketplace/customer

    processing --> shipped : Admin input resi / sync dari marketplace
    processing --> cancelled : Gagal proses

    shipped --> delivered : Kurir konfirmasi pengiriman
    shipped --> cancelled : Retur / gagal kirim

    delivered --> [*]
    cancelled --> [*]

    note right of pending
        payment_status default: paid
        (auto-confirmed by marketplace)
    end note

    note right of shipped
        tracking_number diisi
        shipped_at di-set
    end note

    note right of delivered
        delivered_at di-set
        Stok otomatis berkurang
    end note
```

### Perbedaan Status Flow

| Aspek | ProductOrder | MarketplaceOrder |
| - | - | - |
| **Status awal** | `pending` | `pending` |
| **Enum status** | 4 state: `pending`, `processing`, `completed`, `cancelled` | 5 state: `pending`, `processing`, `shipped`, `delivered`, `cancelled` |
| **Pemicu transfer** | Verifikasi manual oleh admin | Auto-confirm dari marketplace API |
| **State pengiriman** | Implisit dalam `processing` | Eksplisit: `shipped` → `delivered` |
| **Pembatalan** | Bisa oleh customer atau admin | Bergantung kebijakan marketplace |
| **Refund** | Manual via admin | Field `payment_status: refunded` |

***

## Sequence Diagrams — Flow Order

### Flow 1: Penempatan Order Internal (ProductOrder)

```mermaid theme={null}
sequenceDiagram
    participant C as Customer
    participant FE as Frontend (MyOrders.jsx)
    participant API as Supabase API
    participant DB as Database
    participant INV as Inventory System

    C->>FE: Pilih produk & klik "Beli"
    FE->>API: POST /product_orders
    API->>DB: INSERT INTO product_orders (status: pending)
    DB-->>API: Return created order
    API-->>FE: Order created + order_id

    C->>FE: Upload bukti pembayaran
    FE->>API: UPDATE product_orders SET payment_proof_url
    API->>DB: Update order record

    Note over API: Admin mengambil order
    API->>DB: UPDATE SET assigned_to_admin, assigned_at
    API->>INV: Kurangi stok produk
    INV->>DB: INSERT INTO pos_inventories (type: out)
    INV->>DB: UPDATE pos_products SET stock = stock - quantity

    Note over API: Admin menyelesaikan order
    API->>DB: UPDATE SET status = completed, completed_at
    API->>DB: UPDATE SET admin_commission_paid = true

    FE->>API: Polling setiap 10 detik
    API->>DB: SELECT * FROM product_orders WHERE customer_id = $1
    DB-->>FE: Updated order list
    FE->>FE: Diff & re-render changed items
```

### Flow 2: Penempatan Order Marketplace (MarketplaceOrder)

```mermaid theme={null}
sequenceDiagram
    participant C as Customer
    participant MKT as Marketplace (Shopee/Tokopedia)
    participant API as SNISHOP API
    participant DB as Database
    participant INV as Inventory System
    participant NOTIF as Notification Service

    C->>MKT: Checkout di marketplace
    MKT->>API: Webhook: New order received
    API->>DB: INSERT INTO marketplace_orders (status: pending, payment_status: paid)

    loop For each item in order
        API->>INV: Cek stok tersedia
        INV->>DB: SELECT stock FROM pos_products WHERE id = $1
    end

    API->>DB: INSERT INTO pos_inventories (type: out, reason: marketplace_sale)
    API->>DB: UPDATE pos_products SET stock

    Note over API: Admin memproses & input resi
    API->>DB: UPDATE SET status = shipped, tracking_number, shipped_at
    API->>NOTIF: Kirim notifikasi ke customer
    NOTIF->>C: Email/Push: "Pesanan Anda sedang dalam perjalanan"

    MKT->>API: Webhook: Delivery confirmed
    API->>DB: UPDATE SET status = delivered, delivered_at
    API->>DB: Calculate commission_amount, company_amount
```

### Flow 3: Reorder (Pesan Lagi)

```mermaid theme={null}
sequenceDiagram
    participant C as Customer
    participant FE as MyOrders.jsx
    participant CART as MarketplaceCart
    participant API as Supabase API
    participant DB as Database

    C->>FE: Klik "Pesan Lagi" pada order lama
    FE->>DB: SELECT items FROM product_order WHERE id = $1
    DB-->>FE: Return item list

    loop For each item in original order
        FE->>API: POST /marketplace_carts
        API->>DB: INSERT INTO marketplace_carts (product_id, quantity, etc.)
    end

    FE->>CART: Tampilkan cart dengan item terisi
    CART->>C: Review cart → Checkout → Order baru dibuat
```

***

## Dual-Entity Data Model

| Aspek | ProductOrder | MarketplaceOrder |
| - | - | - |
| **Sumber** | Website `/toko` direct checkout | Shopee, Tokopedia, dll |
| **Payment Proof** | Upload manual oleh customer | Auto-confirmed by marketplace |
| **Tracking Number** | Input manual oleh admin | Sync dari marketplace API |
| **Status Flow** | pending → processing → completed → cancelled | pending → processing → shipped → delivered → cancelled |
| **Cancellation** | Admin atau customer | Marketplace-dependent |
| **Struktur Item** | Single-product per order | Multi-item dalam satu order |
| **Fields** | 35+ fields termasuk voucher, komisi, quota | 20+ fields termasuk shipping\_address, komisi |
| **Payment Status** | Implisit dalam status | Eksplisit: `pending`, `paid`, `refunded` |
| **Commission** | `product_commission_rate` + `admin_commission_amount` | `commission_rate` + `commission_amount` + `company_amount` |
| **RLS** | User-scoped (hanya lihat order sendiri) | User-scoped + company-scoped |

***

## Fitur Utama

| Fitur | Deskripsi |
| - | - |
| **Unified View** | Gabungan ProductOrder + MarketplaceOrder dalam satu list |
| **Status Tracking** | Tracking real-time dengan timeline visual per order |
| **Detail Order** | Item, jumlah, harga, total pembayaran, alamat pengiriman |
| **Riwayat** | Riwayat pesanan lengkap yang bisa ditelusuri |
| **Filter Status** | Filter: menunggu pembayaran, diproses, dikirim, selesai, dibatalkan |
| **Aksi Cepat** | Bayar ulang, batalkan pesanan, atau pesan lagi |
| **Auto-Refresh** | Polling 10 detik untuk update status real-time |
| **Notifikasi** | Alert jika ada perubahan status pada pesanan |
| **Multi-Channel** | Badge warna untuk identifikasi sumber order (Website/Marketplace/WhatsApp) |
| **Reorder** | Salin item dari order lama ke keranjang dengan satu klik |
| **Voucher Tracking** | Tampilkan kode voucher yang digunakan dan nominal diskon |
| **Membership Discount** | Otomatis hitung diskon berdasarkan tier membership (regular/silver/gold/platinum) |
| **Reseller Discount** | Diskon bertingkat berdasarkan tier reseller (free: 0%, pro: 5%, business: 10%, advanced: 15%, enterprise: 20%) |

***

## Cara Akses

| Metode | Detail |
| - | - |
| **URL** | `/pos/my-orders` |
| **Sidebar** | Menu **POS** → **My Orders** |
| **Dashboard** | Widget "Pesanan Saya" di Home |

***

## Status & Timeline

```mermaid theme={null}
gantt
    title Timeline Order
    dateFormat HH:mm
    section Status
    Order Dibuat     :done, 00:00, 5min
    Pembayaran       :done, 00:05, 10min
    Verifikasi       :done, 00:15, 5min
    Proses & Kirim   :active, 00:20, 30min
    Selesai          :00:50, 0min
```

| Status | Warna | Deskripsi | Aksi Tersedia |
| - | - | - | - |
| **Menunggu Pembayaran** | Abu-abu | Order dibuat, belum dibayar | Bayar, Batalkan |
| **Diproses** | Biru | Sedang dikemas/disiapkan | Lacak Status |
| **Dikirim** | Kuning | Dalam perjalanan + tracking number | Lacak Kiriman |
| **Selesai** | Hijau | Diterima oleh pelanggan | Pesan Lagi, Review |
| **Dibatalkan** | Merah | Order dibatalkan | — |

***

## Flow Penggunaan

```mermaid theme={null}
flowchart TD
    A[Buka My Orders] --> B[Lihat pesanan aktif]
    B --> C[Klik pesanan untuk detail]
    C --> D{Status pesanan?}
    D -->|Menunggu bayar| E[Klik Bayar untuk lanjutkan]
    D -->|Diproses| F[Lihat timeline status]
    D -->|Selesai| G{Mau pesan lagi?}
    G -->|Ya| H[Klik Pesan Lagi]
    G -->|Tidak| I[Lihat riwayat]
    H --> J[Item masuk cart]
```

***

## Polling & Data Refresh Strategy

```mermaid theme={null}
sequenceDiagram
    participant C as MyOrders.jsx
    participant S as Server
    participant DB as Database

    loop Every 10 seconds
        C->>S: fetchOrders(userId)
        S->>DB: SELECT FROM ProductOrder + MarketplaceOrder
        DB-->>S: Return orders
        S-->>C: Merged order list
        C->>C: Diff & re-render changed items
    end

    Note over C: Cleanup on unmount:<br/>clearInterval(pollingRef)
```

| Parameter | Nilai | Alasan |
| - | - | - |
| **Interval** | 10 detik | Balance antara real-time dan server load |
| **Scope** | User-scoped | Hanya order milik user yang login (RLS) |
| **Cleanup** | `useEffect` return | Mencegah memory leak saat navigasi |
| **Error Handling** | Silent retry | Tidak ganggu user jika server timeout |
| **Data Source** | Dual query | Query ProductOrder dan MarketplaceOrder secara paralel |
| **Merge Strategy** | Unified timeline | Gabungkan berdasarkan `created_at`, sort descending |
| **Diff Algorithm** | Field-level comparison | Hanya re-render card yang berubah (optimasi performa) |

***

## Order Card Components

Setiap order ditampilkan dalam card yang berisi:

| Elemen | Deskripsi |
| - | - |
| **Order ID** | Nomor invoice unik (format: `INV-YYYYMMDD-XXXX`) |
| **Channel Badge** | Badge warna berdasarkan sumber order (Website/Marketplace/WhatsApp) |
| **Status Badge** | Badge warna sesuai status (lihat tabel di atas) |
| **Item Summary** | Nama produk + quantity, dipotong jika > 3 item |
| **Total** | Total pembayaran dalam format Rupiah |
| **Timestamp** | Waktu order dibuat (format relatif: "2 jam yang lalu") |
| **Action Buttons** | Kontekstual sesuai status (Bayar/Lacak/Pesan Lagi) |
| **Voucher Badge** | Tampilkan kode voucher jika digunakan |
| **Membership Badge** | Tampilkan tier membership jika mendapat diskon |

***

## RBAC — Hak Akses per Role

Halaman My Orders menerapkan Row-Level Security (RLS) di Supabase. Setiap role hanya dapat melihat dan mengoperasikan data yang menjadi haknya.

| Role | Lihat Order Sendiri | Lihat Semua Order | Update Status | Batalkan Order | Kelola Inventory |
| - | :-: | :-: | :-: | :-: | :-: |
| **Customer** | Ya | Tidak | Tidak | Ya (hanya status `pending`) | Tidak |
| **Reseller** | Ya | Tidak | Tidak | Ya (hanya status `pending`) | Tidak |
| **Admin/Operator** | Ya | Ya (scope company) | Ya | Ya | Ya (catat inventory) |
| **Super Admin** | Ya | Ya (semua company) | Ya | Ya | Ya |
| **Marketplace Bot** | Tidak | Ya (channel marketplace) | Ya (sync status) | Tidak | Tidak |

### Aturan RLS (Row-Level Security)

| Entitas | Policy | Keterangan |
| - | - | - |
| `ProductOrder` | `customer_id = auth.uid()` | Customer hanya lihat order sendiri |
| `MarketplaceOrder` | `customer_id = auth.uid()` OR `company_id IN (user_companies)` | Customer lihat order sendiri + admin lihat order company-nya |
| `MarketplaceCart` | `user_id = auth.uid()` | Keranjang bersifat privat per user |
| `POSInventory` | `company_id IN (user_companies)` | Inventory hanya untuk admin company terkait |

***

## Keyboard Shortcuts

Untuk meningkatkan efisiensi operasional, halaman My Orders mendukung keyboard shortcut berikut:

| Shortcut | Aksi | Konteks |
| - | - | - |
| `R` | Refresh data manual | Semua halaman |
| `F` | Buka filter status | Semua halaman |
| `Esc` | Tutup panel detail order | Saat detail terbuka |
| `Enter` | Konfirmasi aksi (Bayar/Pesan Lagi) | Saat dialog konfirmasi muncul |
| `Ctrl` + `P` | Print struk order | Order status `completed` |
| `Tab` / `Shift+Tab` | Navigasi antar order card | Daftar order |
| `1` - `5` | Filter status cepat (1=Pending, 2=Processing, 3=Shipped, 4=Completed, 5=Cancelled) | Semua halaman |

***

## Integration Points

Halaman My Orders berintegrasi dengan beberapa subsistem dalam SNISHOP ERP:

| Subsistem | Tipe Integrasi | Deskripsi |
| - | - | - |
| **POS Inventory** | Write-back | Setiap order yang diproses mengurangi stok dan mencatat log di `POSInventory` / `CompanyPOSInventory` |
| **Voucher Engine** | Read + Write | Validasi kode voucher, increment `usage_count`, catat `voucher_code` di order |
| **Membership/Loyalty** | Read | Cek tier membership untuk kalkulasi diskon reseller & member |
| **Marketplace API** | Bi-directional | Webhook masuk untuk order baru, push tracking number ke marketplace |
| **Notification Service** | Write | Kirim notifikasi email/push saat status berubah |
| **Payment Gateway** | Read | Verifikasi status pembayaran untuk order marketplace |
| **Company Settings** | Read | Ambil konfigurasi struk, pajak, dan receipt settings |
| **Digital Product** | Read | Sinkronisasi produk digital ke katalog POS |
| **Discount Engine** | Read | Kalkulasi diskon aktif (percentage, fixed, buy\_x\_get\_y, coupon\_code) |
| **Financial Module** | Write-back | Jurnal otomatis tercatat saat order completed (revenue, COGS, commission) |

***

## Tips

* **Simpan nomor order** untuk referensi jika perlu menghubungi customer service
* **Manfaatkan fitur Pesan Lagi** untuk menghemat waktu jika sering memesan item yang sama
* **Cek tab Riwayat** untuk melihat pesanan lama dan melakukan reorder
* **Perhatikan badge channel** untuk membedakan asal pesanan (website vs marketplace)
* **Gunakan filter status** saat volume pesanan tinggi untuk fokus pada order yang perlu ditindaklanjuti
* **Periksa field `quota_remaining`** pada produk quota-based untuk memastikan ketersediaan sebelum order
* **Manfaatkan voucher & kode kupon** — cek field `voucher_code` pada order untuk melacak diskon yang sudah digunakan
* **Monitor `loyalty_deficit_points`** pada POSMember jika ada pembatalan order yang mempengaruhi poin loyalty
* **Gunakan shortcut `1`-`5`** untuk filter status cepat tanpa perlu klik dropdown
* **Perhatikan `shipping_address`** pada MarketplaceOrder untuk memastikan alamat pengiriman sudah benar sebelum status berubah ke `shipped`


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