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

# Distribution tracking

<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: "Distribution Tracking"
description: "Sistem tracking distribusi, shipment management, batch recall, dan surat jalan di SNISHOP ERP."
-------------------------------------------------------------------------------------------------------------

# Distribution Tracking

<img src="https://mintcdn.com/quinnofspicy/e4f_upKhVWcjsUmM/docs/mintlify/screenshots/b2b/distribution-tracking.png?fit=max&auto=format&n=e4f_upKhVWcjsUmM&q=85&s=b1dc3b07d0f5dfe7892119d0ee8de3c8" alt="Distribution Tracking" width="1920" height="1080" data-path="docs/mintlify/screenshots/b2b/distribution-tracking.png" />

Distribution Tracking adalah modul logistik end-to-end yang mengelola pengiriman dari gudang ke partner atau customer. Modul ini mencakup 8 status pengiriman, integrasi dengan 7 logistic provider, mesin recall batch untuk produk bermasalah, dan generate surat jalan untuk dokumentasi fisik.

Sistem ini dirancang untuk bisnis F\&B manufacturing yang membutuhkan visibilitas penuh atas setiap batch produk yang keluar dari gudang — mulai dari picking, packing, shipping, hingga delivery confirmation. Jika terjadi masalah kualitas pada batch tertentu, fitur batch recall memungkinkan identifikasi dan penarikan produk secara terstruktur.

## Arsitektur Komponen

```mermaid theme={null}
graph TD
    A[DistributionTrackingPage.jsx<br/>1320 lines] --> B[Shipment List<br/>8 Status Types]
    A --> C[Shipment Detail<br/>18+ Fields]
    A --> D[Surat Jalan<br/>Print Preview]
    A --> E[recallEngine.js<br/>280 lines]
    
    B --> F[Status Pipeline<br/>Pending → Confirmed]
    B --> G[Logistic Provider<br/>7 Providers]
    
    C --> H[Batch Information<br/>FIFO Selection]
    C --> I[Recipient Details<br/>Address & Contact]
    
    D --> J[PDF Generation<br/>Company letterhead]
    
    E --> K[Risk Assessment<br/>4 Levels]
    E --> L[CSV Manifest<br/>Affected shipments]
```

## Entity Relationship Diagram

```mermaid theme={null}
erDiagram
    DistributionShipment ||--o{ DistributionReturn : "di-return melalui"
    DistributionShipment }o--|| LotBatch : "melacak batch produk"
    DistributionShipment }o--|| WarehouseLocation : "lokasi asal pengiriman"
    DistributionShipment }o--o| QualityCase : "recall dipicu oleh"
    DistributionShipment }o--o| QuinnOrder : "terkait sales order"

    DistributionReturn }o--|| DistributionShipment : "referensi shipment asal"
    DistributionReturn }o--|| LotBatch : "batch yang di-return"
    DistributionReturn }o--o| WarehouseLocation : "lokasi penerimaan return"
    DistributionReturn }o--o| QualityCheck : "inspeksi QC return"

    LotBatch }o--|| ProductionOrder : "dihasilkan dari produksi"
    LotBatch }o--|| WarehouseLocation : "disimpan di lokasi"
    LotBatch ||--o{ QualityCase : "subject quality hold"
    LotBatch ||--o{ HACCPVerification : "diverifikasi HACCP"
    LotBatch }o--o| QualityCheck : "hasil pemeriksaan QC"
    LotBatch }o--|| PurchaseOrder : "berasal dari PO"

    ProductionOrder ||--o{ HACCPVerification : "verifikasi HACCP"
    ProductionOrder }o--|| WarehouseLocation : "diproduksi di lokasi"

    QualityCase }o--|| LotBatch : "menahan lot batch"

    PurchaseOrder ||--o{ QualityCheck : "diperiksa oleh QC"

    PartnershipApplication ||--o{ DistributionShipment : "menerima pengiriman"

    DistributionShipment {
        string company_id PK "ID perusahaan multi-tenant"
        string shipment_number UK "Nomor pengiriman SHIP-YYYYMMDD-XXX"
        string sales_order_id FK "ID Sales Order terkait"
        string so_number "Nomor Sales Order"
        string customer_id FK "ID customer atau distributor"
        string customer_name "Nama customer"
        enum customer_type "Tipe customer retail reseller distributor modern_market"
        string destination_address "Alamat tujuan pengiriman"
        string destination_city "Kota tujuan"
        date shipment_date "Tanggal kirim"
        date estimated_arrival "Estimasi waktu tiba"
        date actual_arrival "Tanggal diterima aktual"
        array items "Item produk dengan batch tracking"
        number total_quantity "Total kuantitas seluruh item"
        number total_amount "Total nilai pengiriman"
        string logistic_provider "Ekspedisi atau logistik"
        string tracking_number "Nomor resi"
        enum status "Status pengiriman 8 nilai"
        string received_by "Nama penerima saat konfirmasi"
        date received_date "Tanggal penerimaan dikonfirmasi"
        string received_notes "Catatan saat penerimaan"
        boolean is_recalled "Flag recall batch bermasalah"
        string recall_reason "Alasan recall"
        date recall_date "Tanggal recall dilaksanakan"
        string prepared_by "User yang menyiapkan"
        string prepared_by_name "Nama penyiap"
        string notes "Catatan tambahan"
        object metadata "Idempotency dan traceability"
        string invoice_id FK "ID Invoice sell-in otomatis"
        string finance_record_id FK "ID FinancialRecord piutang"
    }

    DistributionReturn {
        string company_id PK "ID perusahaan multi-tenant"
        string return_number UK "Nomor return unik"
        string shipment_id FK "ID shipment yang di-return"
        string shipment_number "Nomor shipment referensi"
        string customer_id FK "ID customer pengreturn"
        string customer_name "Nama customer"
        array items "Item yang di-return dengan detail batch"
        number total_quantity "Total kuantitas return"
        date requested_date "Tanggal permintaan return"
        enum status "Status return 6 nilai"
        datetime received_date "Tanggal barang return diterima"
        string received_by "User yang menerima return"
        string received_location_id FK "Lokasi penerimaan return"
        string quarantine_lot_id "Lot karantina untuk barang return"
        enum quarantine_status "Status karantina 4 nilai"
        enum qc_status "Status quality control 4 nilai"
        number approved_quantity "Kuantitas yang disetujui"
        number rejected_quantity "Kuantitas yang ditolak"
        string disposition_reason "Alasan disposisi akhir"
        datetime disposition_date "Tanggal disposisi"
        string disposition_by "User yang melakukan disposisi"
        string notes "Catatan return"
        object metadata "Metadata teknis"
        string requested_by "User yang meminta return"
        string requested_by_email "Email peminta return"
    }

    LotBatch {
        string company_id PK "ID perusahaan multi-tenant"
        string lot_number UK "Nomor lot batch unik"
        string product_id FK "ID produk"
        string product_name "Nama produk"
        string product_sku "SKU produk"
        string product_type "Tipe produk"
        enum identity_status "Status identitas linked atau legacy_review"
        string production_order_id FK "ID production order pembuat lot"
        number quantity "Jumlah awal dalam lot"
        number quantity_remaining "Jumlah tersisa"
        number current_quantity "Kuantitas lot saat ini dari rilis QC"
        number reserved_quantity "Jumlah yang direservasi"
        date manufacture_date "Tanggal produksi"
        date expiry_date "Tanggal kadaluarsa"
        string location_id FK "ID warehouse location"
        string location_name "Nama lokasi gudang"
        number cost_per_unit "Biaya per unit lot"
        enum status "Status lot 6 nilai"
        enum quality_status "Status kualitas passed failed pending"
        enum item_type "Tipe item finished_good semi_finished raw_material"
        enum expiry_alert_status "Status peringatan kadaluarsa"
        boolean haccp_verified "Sudah diverifikasi HACCP"
        array input_lots "Daftar lot bahan baku penyuplai"
        string supplier_id FK "ID supplier pemasok"
        string purchase_order_id FK "ID Purchase Order asal"
        enum cost_status "Status kelengkapan biaya modal"
        object cost_snapshot "Snapshot rincian komponen biaya"
    }

    WarehouseLocation {
        string company_id PK "ID perusahaan"
        string location_name "Nama lokasi gudang atau toko"
        string location_code UK "Kode unik lokasi"
        enum location_type "Tipe warehouse store transit virtual"
        string description "Penjelasan lokasi dan kapasitas"
        string address "Alamat lengkap"
        string city "Kota"
        string manager_name "Nama pengelola"
        string manager_contact "Kontak pengelola"
        number capacity "Kapasitas maksimal unit atau m2"
        number current_utilization "Utilisasi saat ini persen"
        boolean is_active "Status aktif"
        object coordinates "Koordinat GPS latitude longitude"
    }

    QualityCase {
        string company_id PK "ID perusahaan"
        string lot_batch_id FK "ID LotBatch yang ditahan"
        string product_name "Nama produk snapshot"
        string batch_number "Nomor batch snapshot"
        enum reason "Kategori alasan penahanan"
        string description "Deskripsi rinci temuan"
        array evidence_urls "URL bukti foto dokumen"
        string reported_by "User pelapor"
        datetime reported_at "Waktu pelaporan"
        enum status "Status penanganan 5 nilai"
        string assigned_to "User atau tim penangani"
        string resolution_notes "Catatan resolusi"
        datetime resolved_at "Waktu penyelesaian"
        boolean hold_requested "Apakah quarantine diminta"
        string hold_approved_by "User penyetujui hold"
        datetime hold_approved_at "Waktu hold disetujui"
    }

    QualityCheck {
        string company_id PK "ID perusahaan multi-tenant"
        string qc_number UK "Nomor QC QC-YYYYMMDD-XXX"
        string purchase_order_id FK "ID Purchase Order terkait"
        string supplier_id FK "ID supplier"
        string raw_material_id FK "ID bahan baku diperiksa"
        string batch_id FK "Batch ID bahan baku"
        number quantity_received "Jumlah diterima"
        date qc_date "Tanggal pengecekan"
        string inspector_id "ID QC inspector"
        array checklist "Checklist digital kualitas"
        enum overall_status "Status keseluruhan QC"
        number approved_quantity "Jumlah disetujui"
        number rejected_quantity "Jumlah ditolak"
        boolean inventory_updated "Stok sudah masuk inventory"
    }

    ProductionOrder {
        string company_id PK "ID perusahaan"
        string po_number "Nomor Perintah Produksi"
        string production_batch_id UK "Batch ID PROD-YYYYMMDD-XXX"
        string bom_id FK "ID Bill of Materials"
        string product_id FK "ID produk output"
        string product_name "Nama produk"
        number quantity_to_produce "Jumlah yang diproduksi"
        enum priority "Prioritas low normal high urgent"
        date production_start_date "Tanggal mulai produksi"
        enum status "Status produksi 5 nilai"
        enum qc_result "Hasil QC pass fail pending rework"
        enum production_tier "Tingkat primary_semi atau final_finished"
        boolean haccp_verified "Sudah verifikasi HACCP"
        string output_lot_id FK "ID LotBatch output"
    }

    HACCPVerification {
        string company_id PK "ID perusahaan"
        string haccp_number UK "Nomor HACCP HACCP-YYYYMMDD-XXX"
        string production_order_id FK "ID Production Order"
        string production_batch_id "Batch ID produksi"
        string product_id FK "ID produk"
        string operator_id "ID operator produksi"
        datetime start_time "Waktu mulai produksi"
        enum status "Status verifikasi HACCP"
        enum qc_result "Hasil QC produk jadi"
        number temperature_c "Suhu proses"
        number target_temperature_c "Target suhu"
        boolean temperature_ok "Suhu tercapai"
        array checklist "Checklist HACCP digital"
    }

    QuinnOrder {
        string company_id PK "ID perusahaan"
        string order_number UK "Nomor pesanan unik"
        string customer_name "Nama pelanggan"
        string customer_phone "Nomor WhatsApp"
        string shipping_address "Alamat pengiriman"
        string city "Kota tujuan"
        array items "Daftar produk dipesan"
        number total "Total akhir pembayaran"
        enum payment_method "Metode bayar transfer_bank cod whatsapp"
        enum status "Status pesanan 6 nilai"
        enum payment_status "Status pembayaran 6 nilai"
        enum fulfillment_status "Status fulfillment 6 nilai"
        enum reservation_status "Status reservasi stok 4 nilai"
    }

    PartnershipApplication {
        string company_name "Nama perusahaan pendaftar"
        string contact_name "Nama kontak"
        string contact_email "Email kontak"
        enum partnership_type "Tipe reseller integration community strategic"
        enum status "Status submitted reviewing negotiation approved rejected"
        string business_description "Deskripsi bisnis"
    }
```

## Entity & Model

### DistributionShipment

Entitas utama yang merepresentasikan setiap pengiriman produk dari gudang ke customer/distributor. Setiap shipment terhubung dengan Sales Order, melacak batch produk untuk keperluan recall, dan terintegrasi dengan modul Finance melalui `invoice_id` dan `finance_record_id`.

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `company_id` | String | Ya | ID perusahaan (multi-tenant scoping) |
| `shipment_number` | String | Ya | Nomor pengiriman unik (format: SHIP-YYYYMMDD-XXX) |
| `sales_order_id` | String | Tidak | ID Sales Order terkait |
| `so_number` | String | Tidak | Nomor Sales Order referensi |
| `customer_id` | String | Ya | ID customer/distributor tujuan |
| `customer_name` | String | Tidak | Nama customer/distributor |
| `customer_type` | Enum | Tidak | Tipe customer: `retail`, `reseller`, `distributor`, `modern_market` (default: `distributor`) |
| `destination_address` | String | Tidak | Alamat lengkap tujuan pengiriman |
| `destination_city` | String | Tidak | Kota tujuan pengiriman |
| `shipment_date` | Date | Ya | Tanggal barang dikirim |
| `estimated_arrival` | Date | Tidak | Estimasi waktu tiba di tujuan |
| `actual_arrival` | Date | Tidak | Tanggal aktual barang diterima |
| `items` | Array\[Object] | Tidak | Daftar item produk yang dikirim dengan batch tracking |
| `items[].product_id` | String | - | ID produk yang dikirim |
| `items[].product_name` | String | - | Nama produk |
| `items[].batch_id` | String | - | Batch ID produk jadi untuk recall tracking |
| `items[].lot_number` | String | - | Nomor lot batch fisik |
| `items[].quantity` | Number | - | Jumlah produk yang dikirim |
| `items[].unit` | String | - | Satuan produk |
| `items[].unit_price` | Number | - | Harga satuan |
| `items[].total_price` | Number | - | Total harga per item |
| `total_quantity` | Number | Tidak | Total kuantitas seluruh item (default: 0) |
| `total_amount` | Number | Tidak | Total nilai pengiriman (default: 0) |
| `logistic_provider` | String | Tidak | Nama ekspedisi atau logistik |
| `tracking_number` | String | Tidak | Nomor resi dari logistik |
| `status` | Enum | Tidak | Status pengiriman (default: `pending`) |
| `received_by` | String | Tidak | Nama penerima saat konfirmasi |
| `received_date` | Date | Tidak | Tanggal penerimaan dikonfirmasi |
| `received_notes` | String | Tidak | Catatan saat penerimaan |
| `is_recalled` | Boolean | Tidak | Flag recall untuk batch bermasalah (default: `false`) |
| `recall_reason` | String | Tidak | Alasan recall batch |
| `recall_date` | Date | Tidak | Tanggal recall dilaksanakan |
| `prepared_by` | String | Tidak | User yang menyiapkan pengiriman |
| `prepared_by_name` | String | Tidak | Nama penyiap pengiriman |
| `notes` | String | Tidak | Catatan tambahan |
| `metadata` | Object | Tidak | Server-authoritative idempotency and traceability metadata |
| `invoice_id` | String | Tidak | ID Invoice sell-in yang diposting otomatis saat pengiriman dibuat |
| `finance_record_id` | String | Tidak | ID FinancialRecord piutang (receivable) terkait pengiriman |

### DistributionReturn

Entitas yang mengelola proses retur pengiriman dari customer/distributor. Setiap return terhubung dengan shipment asal, melalui proses QC, karantina, dan disposisi akhir.

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `company_id` | String | Ya | ID perusahaan (multi-tenant) |
| `return_number` | String | Ya | Nomor dokumen return unik |
| `shipment_id` | String | Ya | ID DistributionShipment asal retur |
| `shipment_number` | String | Tidak | Nomor shipment referensi |
| `customer_id` | String | Ya | ID customer yang mengajukan return |
| `customer_name` | String | Tidak | Nama customer |
| `items` | Array\[Object] | Tidak | Daftar item yang di-return |
| `items[].product_id` | String | - | ID produk yang di-return |
| `items[].product_name` | String | - | Nama produk |
| `items[].category_key` | String | - | Kunci kategori produk |
| `items[].category_name` | String | - | Nama kategori |
| `items[].variant_key` | String | - | Kunci varian |
| `items[].variant_name` | String | - | Nama varian |
| `items[].variant_label` | String | - | Label varian |
| `items[].size_grams` | Number | - | Ukuran dalam gram |
| `items[].base_product_key` | String | - | Kunci produk dasar |
| `items[].batch_id` | String | - | Batch ID produk |
| `items[].quantity` | Number | - | Jumlah yang di-return |
| `items[].unit` | String | - | Satuan |
| `items[].reason` | String | - | Alasan return per item |
| `items[].condition` | String | - | Kondisi barang saat return |
| `items[].historical_unit_price` | Number | - | Harga satuan historis saat pengiriman asli |
| `items[].historical_total_price` | Number | - | Total harga historis |
| `items[].price_source` | String | - | Sumber data harga historis |
| `total_quantity` | Number | Tidak | Total kuantitas return |
| `requested_date` | Date | Ya | Tanggal permintaan return diajukan |
| `status` | Enum | Ya | Status return (default: `requested`) |
| `received_date` | DateTime | Tidak | Tanggal barang return diterima di gudang |
| `received_by` | String | Tidak | User yang menerima barang return |
| `received_location_id` | String | Tidak | ID WarehouseLocation penerimaan return |
| `quarantine_lot_id` | String | Tidak | ID lot karantina untuk barang return |
| `quarantine_status` | Enum | Tidak | Status karantina barang return |
| `qc_status` | Enum | Tidak | Status quality control return |
| `approved_quantity` | Number | Tidak | Kuantitas yang disetujui |
| `rejected_quantity` | Number | Tidak | Kuantitas yang ditolak |
| `disposition_reason` | String | Tidak | Alasan disposisi akhir |
| `disposition_date` | DateTime | Tidak | Tanggal disposisi dilakukan |
| `disposition_by` | String | Tidak | User yang melakukan disposisi |
| `notes` | String | Tidak | Catatan tambahan |
| `metadata` | Object | Tidak | Metadata teknis |
| `requested_by` | String | Tidak | User yang meminta return |
| `requested_by_email` | String | Tidak | Email peminta return |

### LotBatch

Entitas yang merepresentasikan setiap batch/lot produksi atau penerimaan bahan baku. LotBatch merupakan tulang punggung traceability — setiap produk yang diproduksi, disimpan, dikirim, atau direcall dapat dilacak melalui nomor lot.

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `company_id` | String | Ya | ID perusahaan (multi-tenant) |
| `lot_number` | String | Ya | Nomor lot/batch unik |
| `product_id` | String | Ya | ID produk terkait |
| `product_name` | String | Tidak | Nama produk |
| `product_sku` | String | Tidak | SKU produk |
| `product_type` | String | Tidak | Jenis produk |
| `identity_status` | Enum | Tidak | Status identitas: `linked`, `legacy_review` |
| `source_material_id` | String | Tidak | ID bahan baku sumber |
| `category_key` | String | Tidak | Key kategori produk |
| `category_name` | String | Tidak | Nama kategori |
| `variant_key` | String | Tidak | Key varian |
| `variant_name` | String | Tidak | Nama varian |
| `variant_label` | String | Tidak | Label varian |
| `size_grams` | Number | Tidak | Ukuran dalam gram |
| `base_product_key` | String | Tidak | Key produk dasar |
| `production_order_id` | String | Tidak | ID production order yang menghasilkan lot |
| `quantity` | Number | Ya | Jumlah awal dalam lot ini |
| `quantity_remaining` | Number | Tidak | Jumlah yang tersisa |
| `current_quantity` | Number | Tidak | Kuantitas lot saat ini (cermin dari quantity\_remaining, ditulis oleh proses rilis QC) |
| `reserved_quantity` | Number | Tidak | Jumlah yang direservasi (default: 0) |
| `manufacture_date` | Date | Tidak | Tanggal produksi |
| `expiry_date` | Date | Tidak | Tanggal kadaluarsa |
| `location_id` | String | Tidak | ID WarehouseLocation penyimpanan |
| `location_name` | String | Tidak | Nama lokasi gudang |
| `cost_per_unit` | Number | Tidak | Biaya per unit untuk lot ini |
| `status` | Enum | Tidak | Status lot batch (default: `active`) |
| `quality_status` | Enum | Tidak | Status kualitas (default: `pending`) |
| `notes` | String | Tidak | Catatan tambahan |
| `warehouse_location_name` | String | Tidak | Nama gudang penyimpanan |
| `rack_location` | String | Tidak | Lokasi rak penyimpanan (misal: A1, B2) |
| `expiry_alert_status` | Enum | Tidak | Status peringatan kadaluarsa (default: `normal`) |
| `haccp_verified` | Boolean | Tidak | Apakah batch sudah diverifikasi HACCP (default: `false`) |
| `item_type` | Enum | Tidak | Tipe item lot batch (default: `finished_good`) |
| `input_lots` | Array\[Object] | Tidak | Daftar lot bahan baku/intermediate yang menyuplai lot ini (genealogy many-to-many) |
| `input_lots[].lot_id` | String | - | ID lot bahan baku |
| `input_lots[].lot_number` | String | - | Nomor lot bahan baku |
| `input_lots[].material_id` | String | - | ID material |
| `input_lots[].material_name` | String | - | Nama material |
| `input_lots[].quantity_used` | Number | - | Jumlah yang digunakan |
| `input_lots[].unit` | String | - | Satuan |
| `input_lots[].allocation_strategy` | String | - | Strategi alokasi |
| `input_lots[].override_reason` | String | - | Alasan penyimpangan FIFO |
| `input_lots[].identity_snapshot` | Object | - | Snapshot identitas canonical bahan |
| `supplier_id` | String | Tidak | ID supplier pemasok |
| `supplier_name` | String | Tidak | Nama supplier |
| `purchase_order_id` | String | Tidak | ID Purchase Order asal penerimaan |
| `delivery_note_number` | String | Tidak | Nomor surat jalan supplier |
| `unit` | String | Tidak | Satuan bahan (kg, gr, pcs, liter) |
| `received_at` | DateTime | Tidak | Waktu penerimaan fisik di gudang |
| `claimed_quantity` | Number | Tidak | Kuantitas menurut surat jalan supplier |
| `weighed_quantity` | Number | Tidak | Kuantitas timbang ulang aktual |
| `accepted_quantity` | Number | Tidak | Kuantitas diterima lolos QC |
| `rejected_quantity` | Number | Tidak | Kuantitas sortasi reject |
| `cost_status` | Enum | Tidak | Status kelengkapan biaya modal (default: `complete`) |
| `rounding_residual` | Number | Tidak | Residual pembulatan alokasi HPP (default: 0) |
| `cost_snapshot` | Object | Tidak | Snapshot rincian komponen biaya |

### WarehouseLocation

Entitas yang mendefinisikan lokasi-lokasi gudang, toko, transit, dan virtual dalam sistem ERP. Setiap shipment memiliki origin dan destination yang merujuk ke WarehouseLocation.

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `company_id` | String | Ya | ID perusahaan |
| `location_name` | String | Ya | Nama lokasi (Gudang Utama, Toko Cabang A, dll) |
| `location_code` | String | Ya | Kode unik lokasi |
| `location_type` | Enum | Tidak | Tipe lokasi (default: `warehouse`) |
| `description` | String | Tidak | Penjelasan lokasi, kapasitas, dan jenis barang (maks 1000 karakter) |
| `address` | String | Tidak | Alamat lengkap lokasi |
| `city` | String | Tidak | Kota lokasi |
| `manager_name` | String | Tidak | Nama penanggung jawab |
| `manager_contact` | String | Tidak | Kontak penanggung jawab |
| `capacity` | Number | Tidak | Kapasitas maksimal (unit atau m2) |
| `current_utilization` | Number | Tidak | Utilisasi saat ini dalam persen (default: 0) |
| `is_active` | Boolean | Tidak | Status aktif (default: `true`) |
| `coordinates` | Object | Tidak | Koordinat GPS (latitude, longitude) |

### QualityCase

Entitas yang menangani kasus kualitas yang menyebabkan penahanan (hold/quarantine) batch produk. QualityCase menjadi trigger utama untuk proses recall pada Distribution Tracking.

| Field | Tipe | Required | Deskripsi |
| - | - | - | - |
| `company_id` | String | Ya | ID perusahaan pemilik quality case |
| `lot_batch_id` | String | Ya | ID LotBatch yang menjadi objek hold |
| `product_name` | String | Tidak | Nama produk lot (snapshot saat case dibuka) |
| `batch_number` | String | Tidak | Nomor lot/batch fisik (snapshot saat case dibuka) |
| `reason` | Enum | Tidak | Kategori alasan penahanan batch |
| `description` | String | Tidak | Deskripsi rinci temuan kualitas |
| `evidence_urls` | Array\[String] | Tidak | Daftar URL bukti foto/dokumen |
| `reported_by` | String | Ya | Email/ID user pelapor |
| `reported_at` | DateTime | Ya | Waktu quality case dilaporkan |
| `status` | Enum | Tidak | Status penanganan (default: `open`) |
| `assigned_to` | String | Tidak | User/tim penangani |
| `resolution_notes` | String | Tidak | Catatan resolusi |
| `resolved_at` | DateTime | Tidak | Waktu case diselesaikan |
| `hold_requested` | Boolean | Tidak | Apakah quarantine diminta (default: `false`) |
| `hold_approved_by` | String | Tidak | User penyetujui hold |
| `hold_approved_at` | DateTime | Tidak | Waktu hold disetujui |

## Status Pipelines & Lifecycle Diagrams

### Shipment Status Lifecycle

```mermaid theme={null}
stateDiagram-v2
    [*] --> Pending: Shipment dibuat
    Pending --> Processing: Barang mulai diproses di gudang
    Processing --> Shipped: Diserahkan ke logistik / surat jalan dicetak
    Shipped --> InTransit: Dalam perjalanan di logistik partner
    InTransit --> Delivered: Barang sampai di tujuan
    Delivered --> Confirmed: Penerima mengkonfirmasi penerimaan
    
    Pending --> Returned: Dibatalkan atau ditolak sebelum diproses
    Processing --> Returned: Dibatalkan saat proses
    Shipped --> Returned: Dikembalikan ke gudang (gagal kirim)
    InTransit --> Returned: Dikembalikan saat dalam perjalanan
    
    Confirmed --> Recalled: Batch bermasalah ditemukan setelah penerimaan
    Delivered --> Recalled: Batch bermasalah ditemukan sebelum konfirmasi
    
    Confirmed --> [*]
    Recalled --> [*]
    Returned --> [*]
```

### Distribution Return Lifecycle

```mermaid theme={null}
stateDiagram-v2
    [*] --> Requested: Customer mengajukan return
    Requested --> Received: Barang return diterima di gudang
    Received --> QC_Pending: Menunggu pemeriksaan QC
    QC_Pending --> Approved: QC menyetujui return
    QC_Pending --> Rejected: QC menolak return
    Approved --> Closed: Disposisi final selesai
    Rejected --> Closed: Return ditutup setelah penolakan
    Closed --> [*]
    
    Requested --> Rejected: Ditolak langsung tanpa penerimaan
```

### Quarantine Status Lifecycle (DistributionReturn)

```mermaid theme={null}
stateDiagram-v2
    [*] --> Pending: Barang return diterima
    Pending --> Quarantined: Barang dikarantina di lot terpisah
    Quarantined --> Released: Lolos QC, dilepas ke stok normal
    Quarantined --> WriteOff: Tidak lolos QC, dihapus dari stok
    Released --> [*]
    WriteOff --> [*]
```

### Lot Batch Status Lifecycle

```mermaid theme={null}
stateDiagram-v2
    [*] --> Active: Lot batch dibuat dari produksi atau penerimaan
    Active --> Quarantine: Ditahan untuk pemeriksaan QC
    Quarantine --> Released: Lolos QC dan siap digunakan
    Quarantine --> Active: Dilepaskan tanpa kondisi khusus
    Released --> Depleted: Kuantitas habis terpakai
    Active --> Expired: Melewati tanggal kadaluarsa
    Released --> Expired: Melewati tanggal kadaluarsa
    Active --> Recalled: Batch ditarik karena masalah kualitas
    Released --> Recalled: Batch ditarik karena masalah kualitas
    Depleted --> [*]
    Expired --> [*]
    Recalled --> [*]
```

### Quality Case Lifecycle

```mermaid theme={null}
stateDiagram-v2
    [*] --> Open: Temuan kualitas dilaporkan
    Open --> Investigating: Tim mulai investigasi
    Investigating --> OnHold: Lot dikarantina selama investigasi
    OnHold --> Investigating: Investigasi dilanjutkan
    Investigating --> Resolved: Temuan diselesaikan
    Resolved --> Closed: Case ditutup secara administratif
    Closed --> [*]
```

### QuinnOrder Fulfillment Lifecycle

```mermaid theme={null}
stateDiagram-v2
    [*] --> Unprocessed: Order baru diterima
    Unprocessed --> Processing: Order mulai diproses
    Processing --> Ready: Barang siap dikirim
    Ready --> Shipped: Barang dikirim ke customer
    Shipped --> Delivered: Barang diterima customer
    Shipped --> Returned: Barang dikembalikan
    
    Unprocessed --> [*]: Order dibatalkan
    Processing --> [*]: Order dibatalkan
```

## Enum Reference Tables

### DistributionShipment Status

| Status | Kode | Deskripsi |
| - | - | - |
| Pending | `pending` | Shipment baru dibuat, belum diproses di gudang |
| Processing | `processing` | Barang sedang diproses (picking, packing) di gudang |
| Shipped | `shipped` | Barang sudah diserahkan ke logistik / surat jalan dicetak |
| In Transit | `in_transit` | Dalam perjalanan di logistik partner |
| Delivered | `delivered` | Barang sampai di tujuan pengiriman |
| Confirmed | `confirmed` | Penerima mengkonfirmasi penerimaan dengan tanda tangan |
| Returned | `returned` | Barang dikembalikan ke gudang (gagal kirim atau retur) |
| Recalled | `recalled` | Batch produk ditarik karena masalah kualitas setelah pengiriman |

### Customer Type

| Tipe | Kode | Deskripsi |
| - | - | - |
| Retail | `retail` | Customer perorangan/ritel |
| Reseller | `reseller` | Penjual ulang produk |
| Distributor | `distributor` | Distributor regional/lokal (default) |
| Modern Market | `modern_market` | Pasar modern (supermarket, minimarket) |

### Logistic Providers

| Provider | Tipe | Coverage |
| - | - | - |
| JNE | Kurir nasional | Seluruh Indonesia |
| J\&T Express | Kurir nasional | Seluruh Indonesia |
| SiCepat | Kurir nasional | Seluruh Indonesia |
| Anteraja | Kurir nasional | Seluruh Indonesia |
| GoSend | Instant/same-day | Kota besar (Java) |
| GrabExpress | Instant/same-day | Kota besar (Java) |
| Internal Fleet | Internal | Area lokal gudang |

### Distribution Return Status

| Status | Kode | Deskripsi |
| - | - | - |
| Requested | `requested` | Customer mengajukan permintaan retur |
| Received | `received` | Barang retur diterima di gudang |
| QC Pending | `qc_pending` | Menunggu inspeksi Quality Control |
| Approved | `approved` | Retur disetujui setelah QC |
| Rejected | `rejected` | Retur ditolak setelah QC |
| Closed | `closed` | Proses retur selesai (disposisi final) |

### Distribution Return Quarantine Status

| Status | Kode | Deskripsi |
| - | - | - |
| Pending | `pending` | Menunggu keputusan karantina |
| Quarantined | `quarantined` | Barang dikarantina di lot terpisah |
| Released | `released` | Dilepas dari karantina ke stok normal |
| Write Off | `write_off` | Dihapus dari inventori (rusak/tidak layak) |

### Distribution Return QC Status

| Status | Kode | Deskripsi |
| - | - | - |
| Pending | `pending` | Menunggu inspeksi QC |
| Approved | `approved` | Lolos inspeksi QC |
| Rejected | `rejected` | Tidak lolos inspeksi QC |
| Conditional | `conditional` | Diterima dengan syarat tertentu |

### Lot Batch Status

| Status | Kode | Deskripsi |
| - | - | - |
| Active | `active` | Lot baru dibuat, menunggu proses QC |
| Released | `released` | Lolos QC, tersedia untuk produksi atau pengiriman |
| Quarantine | `quarantine` | Ditahan untuk investigasi kualitas |
| Expired | `expired` | Melebihi tanggal kadaluarsa |
| Depleted | `depleted` | Stok lot habis terpakai sepenuhnya |
| Recalled | `recalled` | Lot ditarik karena masalah kualitas |

### Lot Batch Quality Status

| Status | Kode | Deskripsi |
| - | - | - |
| Passed | `passed` | Lolos inspeksi kualitas |
| Failed | `failed` | Tidak lolos inspeksi kualitas |
| Pending | `pending` | Menunggu inspeksi kualitas |

### Lot Batch Item Type

| Tipe | Kode | Deskripsi |
| - | - | - |
| Finished Good | `finished_good` | Produk jadi siap jual (default) |
| Semi Finished | `semi_finished` | Produk setengah jadi (intermediate) |
| Raw Material | `raw_material` | Bahan baku mentah |

### Lot Batch Expiry Alert Status

| Status | Kode | Deskripsi |
| - | - | - |
| Normal | `normal` | Jauh dari tanggal kadaluarsa |
| Near Expiry | `near_expiry` | Mendekati kadaluarsa (H-30 hari) |
| Critical Expiry | `critical_expiry` | Kritis mendekati kadaluarsa (H-7 hari) |
| Expired | `expired` | Sudah melewati tanggal kadaluarsa |

### Lot Batch Cost Status

| Status | Kode | Deskripsi |
| - | - | - |
| Complete | `complete` | Seluruh biaya modal telah tercatat lengkap |
| Provisional Incomplete | `provisional_incomplete` | Biaya belum lengkap, masih provisional |
| Unassigned | `unassigned` | Biaya belum diassign ke lot |

### Lot Batch Identity Status

| Status | Kode | Deskripsi |
| - | - | - |
| Linked | `linked` | Identitas lot terhubung ke canonical product master |
| Legacy Review | `legacy_review` | Identitas perlu review manual (data lama/migrasi) |

### Quality Case Reason

| Alasan | Kode | Deskripsi |
| - | - | - |
| Contamination | `contamination` | Kontaminasi fisik, kimia, atau biologis |
| Labeling Error | `labeling_error` | Kesalahan label (informasi, expired date, komposisi) |
| Expired | `expired` | Produk ditemukan sudah kadaluarsa |
| Customer Complaint | `customer_complaint` | Keluhan dari customer terkait kualitas |
| Packaging Defect | `packaging_defect` | Cacat pada kemasan (segel rusak, bocor, dll) |
| Other | `other` | Alasan lainnya |

### Quality Case Status

| Status | Kode | Deskripsi |
| - | - | - |
| Open | `open` | Case baru dilaporkan, belum ditangani |
| Investigating | `investigating` | Tim sedang melakukan investigasi |
| On Hold | `on_hold` | Lot dikarantina, investigasi ditunda sementara |
| Resolved | `resolved` | Temuan telah diselesaikan |
| Closed | `closed` | Case ditutup secara administratif |

### Warehouse Location Type

| Tipe | Kode | Deskripsi |
| - | - | - |
| Warehouse | `warehouse` | Gudang penyimpanan utama |
| Store | `store` | Toko/cabang retail |
| Transit | `transit` | Gudang transit / hub distribusi |
| Virtual | `virtual` | Lokasi virtual (stok dalam perjalanan, quarantine, dll) |

### Quality Check Overall Status

| Status | Kode | Deskripsi |
| - | - | - |
| Pending | `pending` | Menunggu hasil pemeriksaan |
| Approved | `approved` | Hasil pemeriksaan disetujui |
| Rejected | `rejected` | Hasil pemeriksaan ditolak |
| Conditional | `conditional` | Disetujui dengan syarat tertentu |

### Quality Check Expiry Date Check

| Status | Kode | Deskripsi |
| - | - | - |
| Valid | `valid` | Tanggal expired masih valid |
| Expired | `expired` | Barang sudah kadaluarsa |
| Near Expiry | `near_expiry` | Mendekati tanggal kadaluarsa |
| No Date | `no_date` | Tidak ada tanggal expired pada barang |

### Quality Check Checklist Result

| Hasil | Kode | Deskripsi |
| - | - | - |
| Pass | `pass` | Item pengecekan memenuhi standar |
| Fail | `fail` | Item pengecekan tidak memenuhi standar |
| Warning | `warning` | Item mendekati batas toleransi |
| N/A | `na` | Item tidak applicable atau tidak diperiksa |

### QuinnOrder Status

| Status | Kode | Deskripsi |
| - | - | - |
| Pending | `pending` | Order baru diterima, menunggu verifikasi |
| Confirmed | `confirmed` | Order dikonfirmasi |
| Processing | `processing` | Order sedang diproses |
| Shipped | `shipped` | Order sudah dikirim |
| Completed | `completed` | Order selesai |
| Cancelled | `cancelled` | Order dibatalkan |

### QuinnOrder Payment Status

| Status | Kode | Deskripsi |
| - | - | - |
| Unpaid | `unpaid` | Belum ada pembayaran |
| Pending Verification | `pending_verification` | Bukti transfer menunggu verifikasi |
| Partially Paid | `partially_paid` | Pembayaran sebagian |
| Paid | `paid` | Pembayaran lunas terverifikasi |
| Rejected | `rejected` | Bukti pembayaran ditolak |
| Refunded | `refunded` | Dana dikembalikan |

### QuinnOrder Fulfillment Status

| Status | Kode | Deskripsi |
| - | - | - |
| Unprocessed | `unprocessed` | Order belum diproses |
| Processing | `processing` | Order sedang diproses |
| Ready | `ready` | Barang siap dikirim |
| Shipped | `shipped` | Barang sudah dikirim |
| Delivered | `delivered` | Barang sudah diterima |
| Returned | `returned` | Barang dikembalikan |

### QuinnOrder Reservation Status

| Status | Kode | Deskripsi |
| - | - | - |
| Active | `active` | Reservasi stok aktif |
| Consumed | `consumed` | Reservasi sudah digunakan |
| Released | `released` | Reservasi dilepaskan |
| Expired | `expired` | Reservasi kedaluwarsa |

### Partnership Application Type

| Tipe | Kode | Deskripsi |
| - | - | - |
| Reseller | `reseller` | Kemitraan jual ulang produk |
| Integration | `integration` | Integrasi sistem/API |
| Community | `community` | Kemitraan komunitas |
| Strategic | `strategic` | Kemitraan strategis |

### Partnership Application Status

| Status | Kode | Deskripsi |
| - | - | - |
| Submitted | `submitted` | Aplikasi baru diajukan |
| Reviewing | `reviewing` | Sedang ditinjau |
| Negotiation | `negotiation` | Dalam tahap negosiasi |
| Approved | `approved` | Aplikasi disetujui |
| Rejected | `rejected` | Aplikasi ditolak |

## Sequence Diagrams

### Flow Pembuatan Shipment (Create Shipment)

```mermaid theme={null}
sequenceDiagram
    participant ADM as Admin Gudang
    participant DT as DistributionTracking
    participant LB as LotBatch
    participant SM as StockMovement
    participant WL as WarehouseLocation
    participant LP as Logistic Provider
    participant FIN as Finance

    ADM->>DT: Buat shipment baru
    DT->>LB: Query batch tersedia dengan FIFO
    LB-->>DT: Daftar batch + quantity remaining
    DT->>DT: Pilih batch tertua dan alokasikan quantity
    DT->>LB: Kurangi quantity_remaining batch terpilih
    DT->>SM: Catat StockMovement tipe out
    DT->>WL: Validasi lokasi asal pengiriman
    DT->>LP: Kirim data dan minta tracking number
    LP-->>DT: tracking_number
    DT->>DT: Generate shipment_number (SHIP-YYYYMMDD-XXX)
    DT->>FIN: Posting Invoice sell-in dan FinancialRecord piutang
    FIN-->>DT: invoice_id, finance_record_id
    DT->>DT: Set status = "pending"
    DT-->>ADM: Shipment berhasil dibuat
```

### Flow Tracking & Status Update

```mermaid theme={null}
sequenceDiagram
    participant LP as Logistic Provider
    participant DT as DistributionTracking
    participant P as B2B Partner Portal
    participant N as Notification Service

    LP->>DT: Webhook: status update (in_transit)
    DT->>DT: Validate dan update shipment status
    DT->>DT: Update estimated_arrival
    
    DT->>P: Push status update ke partner
    DT->>N: Send notification ke partner
    
    LP->>DT: Webhook: status update (delivered)
    DT->>DT: Update status = "delivered"
    DT->>DT: Set actual_arrival
    
    DT->>P: Push delivery confirmation
    DT->>N: Notify partner untuk konfirmasi penerimaan
    
    P->>DT: Partner confirms receipt (received_by, received_notes)
    DT->>DT: Update status = "confirmed"
```

### Flow Batch Recall

```mermaid theme={null}
sequenceDiagram
    participant QC as Quality Control
    participant RE as recallEngine
    participant DS as DistributionShipment
    participant LB as LotBatch
    participant DR as DistributionReturn
    participant SM as StockMovement

    QC->>RE: Laporkan masalah kualitas pada batch
    RE->>RE: Assess risk level (LOW/MEDIUM/HIGH/CRITICAL)
    RE->>DS: Query semua shipment mengandung batch terdampak
    DS-->>RE: Daftar shipment terdampak
    RE->>LB: Update status lot batch menjadi recalled
    
    alt HIGH atau CRITICAL
        RE->>RE: Generate CSV manifest penerima terdampak
        RE->>DS: Set is_recalled = true, status = "recalled"
        RE->>DR: Buat DistributionReturn untuk shipment terdampak
        DR->>SM: Catat StockMovement tipe return
        RE-->>QC: Manifest CSV dan daftar return siap
    else MEDIUM
        RE->>DR: Siapkan DistributionReturn
        RE-->>QC: Notifikasi partner dan siapkan replacement
    else LOW
        RE-->>QC: Log dan monitor tanpa aksi langsung
    end
```

### Flow Distribution Return

```mermaid theme={null}
sequenceDiagram
    participant CUST as Customer
    participant DR as DistributionReturn
    participant DS as DistributionShipment
    participant QC as QualityCheck
    participant LB as LotBatch
    participant SM as StockMovement
    participant WL as WarehouseLocation

    CUST->>DR: Ajukan permintaan return dengan alasan
    DR->>DS: Validasi referensi shipment dan batch
    DS-->>DR: Data shipment dan item terkonfirmasi
    DR->>DR: Set status = "requested"
    
    DR->>WL: Terima barang return di lokasi gudang
    DR->>DR: Set status = "received", quarantine_status = "quarantined"
    DR->>LB: Buat lot karantina untuk barang return
    
    DR->>QC: Jadikan pemeriksaan QC (status: qc_pending)
    QC->>QC: Inspeksi kondisi barang
    
    alt Approved
        QC-->>DR: QC approved (qc_status: approved)
        DR->>SM: Catat StockMovement tipe return ke inventory
        DR->>DR: Set status = "approved"
    else Rejected
        QC-->>DR: QC rejected (qc_status: rejected)
        DR->>DR: Set status = "rejected"
    else Conditional
        QC-->>DR: QC conditional (qc_status: conditional)
        DR->>SM: Catat StockMovement return sebagian
    end
    
    DR->>DR: Disposisi akhir, set status = "closed"
    DR-->>CUST: Konfirmasi return selesai
```

### Flow Surat Jalan Generation

```mermaid theme={null}
sequenceDiagram
    participant U as User (Admin/Gudang)
    participant DT as DistributionTracking
    participant SJ as Surat Jalan Generator
    participant PDF as PDF Engine
    participant P as Printer

    U->>DT: Select shipment, klik "Cetak Surat Jalan"
    DT->>SJ: Gather shipment data
    
    SJ->>SJ: Load company letterhead
    SJ->>SJ: Format shipment_number, shipment_date
    SJ->>SJ: Format recipient (customer_name, destination_address)
    SJ->>SJ: Build item list (items[].product_name, items[].quantity)
    SJ->>SJ: Include batch numbers (items[].batch_id, items[].lot_number)
    SJ->>SJ: Calculate total items (sum of items[].quantity)
    SJ->>SJ: Add signature area (prepared_by + received_by)
    
    SJ->>PDF: Generate PDF preview
    PDF-->>U: Preview surat jalan
    
    U->>P: Print surat jalan
```

## Fitur Utama

### 1. Shipment Management

Sistem membuat shipment baru dengan langkah-langkah terstruktur: validasi stok, pemilihan batch FIFO, pengisian data penerima, pemilihan logistik, dan integrasi ke modul Finance.

**FIFO Batch Selection**: Sistem secara otomatis memilih batch tertua (First In, First Out) untuk memastikan produk yang dikirim memiliki sisa shelf life maksimal. Ini kritis untuk bisnis F\&B karena berkaitan langsung dengan keamanan pangan dan kepuasan customer.

**Idempotency & Data Integrity**: Setiap shipment creation menggunakan **idempotency key** yang tersimpan di field `metadata` untuk mencegah duplikasi, terutama penting saat integrasi dengan API logistik pihak ketiga.

### 2. Surat Jalan (Delivery Order)

Surat Jalan adalah dokumen fisik yang menyertai pengiriman. Sistem menggenerate preview surat jalan yang bisa dicetak:

| Informasi di Surat Jalan | Sumber |
| - | - |
| Company letterhead | Company profile |
| Shipment number | DistributionShipment.shipment\_number |
| Date | DistributionShipment.shipment\_date |
| Recipient name & address | customer\_name, destination\_address |
| Product list | items\[].product\_name + items\[].quantity |
| Batch numbers | items\[].batch\_id / items\[].lot\_number |
| Total items | Sum of items\[].quantity |
| Signature area | prepared\_by + received\_by |

### 3. Batch Recall Engine

`recallEngine.js` (280 baris) adalah modul kritis yang menangani penarikan batch produk bermasalah. Sistem ini digunakan ketika ada laporan kualitas negatif pada batch tertentu dan terhubung langsung dengan entitas `QualityCase`.

**Risk Levels**:

| Level | Kode | Aksi |
| - | - | - |
| LOW | `LOW` | Monitor, investigasi internal |
| MEDIUM | `MEDIUM` | Notifikasi partner, siapkan replacement |
| HIGH | `HIGH` | Recall aktif, hubungi semua penerima batch |
| CRITICAL | `CRITICAL` | Immediate recall, stop semua pengiriman batch terkait |

**Recall Flow**:

```mermaid theme={null}
flowchart TD
    A[Laporan Masalah Kualitas Batch] --> B{recallEngine.assess}
    B --> C[Determine Risk Level]
    
    C --> D[LOW]
    C --> E[MEDIUM]
    C --> F[HIGH]
    C --> G[CRITICAL]
    
    D --> H[Log & Monitor]
    
    E --> I[Query shipments with batch]
    I --> J[Notify affected partners]
    J --> K[Prepare replacement stock]
    
    F --> L[Query all affected shipments]
    L --> M[Generate CSV manifest]
    M --> N[Contact all recipients]
    N --> O[Arrange pickup/return]
    
    G --> P[IMMEDIATE ACTION]
    P --> Q[Stop all pending shipments]
    Q --> R[Emergency contact all recipients]
    R --> S[Arrange immediate pickup]
    S --> T[Quarantine returned stock]
```

**CSV Manifest Export**: Untuk risk level HIGH dan CRITICAL, sistem mengexport CSV manifest yang berisi:

| Kolom | Isi |
| - | - |
| shipment\_number | Nomor pengiriman |
| recipient\_name | Nama penerima |
| recipient\_phone | Nomor telepon |
| address | Alamat lengkap |
| batch\_number | Nomor batch |
| product\_name | Nama produk |
| quantity | Jumlah yang dikirim |
| shipment\_date | Tanggal pengiriman |
| status | Status pengiriman saat ini |

### 4. Tracking & ETA

Setiap shipment memiliki estimasi waktu tiba (ETA) yang bisa diupdate berdasarkan status:

| Status Change | ETA Update |
| - | - |
| Pending → Processing | Persiapan di gudang dimulai |
| Processing → Shipped | ETA dihitung dari SLA logistik |
| Shipped → In Transit | ETA dikonfirmasi, bisa diupdate oleh logistik |
| In Transit → Delivered | actual\_arrival dicatat |
| Delivered → Confirmed | Penerima mengkonfirmasi, proses selesai |

### 5. Distribution Return Management

Modul retur mengelola proses pengembalian barang dari customer/distributor secara terstruktur:

1. **Pengajuan Retur**: Customer mengajukan retur dengan menyebutkan item, quantity, dan alasan
2. **Penerimaan Fisik**: Barang diterima di gudang, dicatat lokasi penerimaannya (`received_location_id`)
3. **Inspeksi QC**: Barang melalui inspeksi Quality Control (`qc_status: pending`)
4. **Karantina**: Barang dikarantina sementara menunggu hasil QC (`quarantine_status: quarantined`)
5. **Disposisi**: Keputusan akhir — approved (kembali ke stok), rejected (write-off), atau conditional

### 6. Multi-Tenant & Row-Level Security

Semua entitas Distribution Tracking menggunakan Row-Level Security (RLS) berbasis `company_id`. Akses data dibatasi berdasarkan:

* **Company scoping**: User hanya melihat data dari `active_company_id` mereka
* **Creator access**: User yang membuat record dapat mengakses record tersebut
* **Admin override**: User dengan role `admin` memiliki akses penuh

## Cara Akses

Dari sidebar, klik menu **B2B** > **Distribution Tracking**.

## Flow Penggunaan

### Admin / Gudang

1. Buka halaman Distribution Tracking dari sidebar
2. Klik "Buat Pengiriman" untuk shipment baru
3. Pilih produk dan jumlah yang akan dikirim
4. Sistem otomatis memilih batch tertua (FIFO)
5. Isi detail penerima dan alamat
6. Pilih logistic provider dan input tracking number
7. Print surat jalan untuk menyertai pengiriman
8. Update status secara berkala seiring progres pengiriman

### Batch Recall (Quality Issue)

1. Terima laporan kualitas negatif pada batch tertentu
2. Aktifkan recallEngine dengan batch number
3. Sistem assess risk level (LOW/MEDIUM/HIGH/CRITICAL)
4. Untuk HIGH/CRITICAL: export CSV manifest penerima terdampak
5. Hubungi penerima untuk arrange return/pickup
6. Update status shipment ke `returned` atau `recalled`
7. Quarantine stock yang dikembalikan
8. Buat DistributionReturn untuk proses retur formal

### Retur Barang

1. Customer/distributor mengajukan permintaan retur
2. Sistem membuat DistributionReturn dengan status `requested`
3. Jadwalkan penerimaan barang di gudang
4. Terima barang fisik, update status ke `received`
5. Inspeksi QC terhadap barang retur
6. Tentukan disposisi: approved, rejected, atau conditional
7. Update stok sesuai disposisi akhir
8. Tutup proses retur (status: `closed`)

## Integrasi Cross-Module

```mermaid theme={null}
graph LR
    A[Distribution Tracking] --> B[Inventory / LotBatch<br/>Stock & batch]
    A --> C[B2B Partner Portal<br/>Shipment visibility]
    A --> D[Finance<br/>Invoice, receivable, GL]
    A --> E[Manufacturing / ProductionOrder<br/>Batch traceability]
    A --> F[Quality Control / QualityCase<br/>Recall engine]
    A --> G[WarehouseLocation<br/>Origin & destination]
    A --> H[HACCP Verification<br/>Food safety compliance]
    A --> I[QuinnOrder<br/>D2C order fulfillment]
    
    B --> J[FIFO batch selection]
    C --> K[Partner sees status]
    D --> L[GL journal entry, AR tracking]
    E --> M[Batch → Product → Shipment]
    F --> N[Recall manifest, QualityCase]
    G --> O[Multi-location tracking]
    H --> P[HACCP compliance per batch]
    I --> Q[Website order → shipment]
```

### Detail Integrasi

| Modul Terintegrasi | Arah | Deskripsi |
| - | - | - |
| **Inventory (LotBatch)** | Bidirectional | Shipment mengambil stok dari LotBatch (FIFO), update quantity\_remaining saat shipped |
| **Finance** | Outbound | Shipment membuat invoice otomatis (`invoice_id`) dan FinancialRecord piutang (`finance_record_id`) |
| **Quality Control (QualityCase)** | Bidirectional | QualityCase memicu recall pada shipment; QualityCheck memverifikasi barang retur |
| **Manufacturing (ProductionOrder)** | Inbound | ProductionOrder menghasilkan LotBatch yang kemudian dikirim via DistributionShipment |
| **Warehouse (WarehouseLocation)** | Inbound | WarehouseLocation menjadi origin (gudang asal) dan destination untuk retur |
| **HACCP (HACCPVerification)** | Inbound | HACCPVerification memastikan batch yang dikirim memenuhi standar keamanan pangan |
| **QuinnOrder** | Inbound | Order dari website (D2C) dapat dikonversi menjadi DistributionShipment |
| **B2B Partner Portal** | Outbound | Partner dapat melihat status shipment mereka secara real-time |

## RBAC Permission Matrix

Berdasarkan Row-Level Security (RLS) yang didefinisikan pada setiap entitas:

| Entitas | Operasi | Admin | Owner (Creator) | Same Company |
| - | - | - | - | - |
| DistributionShipment | Create | Ya | Ya | Ya (validasi company\_id) |
| DistributionShipment | Read | Ya | Ya | Ya (validasi company\_id) |
| DistributionShipment | Update | Ya | Ya | Ya (validasi company\_id) |
| DistributionShipment | Delete | Ya | Ya | Ya (validasi company\_id) |
| DistributionReturn | Create | Ya | Ya | Ya (validasi company\_id) |
| DistributionReturn | Read | Ya | Ya | Ya (validasi company\_id) |
| DistributionReturn | Update | Ya | Ya | Ya (validasi company\_id) |
| DistributionReturn | Delete | Ya | Ya | Ya (validasi company\_id) |
| LotBatch | Create | Ya | - | Ya |
| LotBatch | Read | Ya | - | Ya |
| LotBatch | Update | Ya | - | Ya |
| LotBatch | Delete | Ya | - | Ya |
| WarehouseLocation | Create | Ya | - | Ya |
| WarehouseLocation | Read | Ya | - | Ya |
| WarehouseLocation | Update | Ya | - | Ya |
| WarehouseLocation | Delete | Ya | - | Ya |
| QualityCheck | Create | Ya | - | Ya |
| QualityCheck | Read | Ya | - | Ya |
| QualityCheck | Update | Ya | - | Ya |
| QualityCheck | Delete | Ya | - | Ya |
| QualityCase | Create | Ya | - | Ya |
| QualityCase | Read | Ya | - | Ya |
| QualityCase | Update | Ya | - | Ya |
| QualityCase | Delete | Ya | - | Ya |

**Catatan RBAC**:

* **Admin**: Akses penuh ke semua operasi CRUD pada semua entitas dalam perusahaan.
* **Owner (Creator)**: Khusus DistributionShipment dan DistributionReturn, user yang membuat record memiliki akses penuh terlepas dari company\_id.
* **Same Company**: User dalam company yang sama dapat mengakses data selama `company_id` pada data cocok dengan `active_company_id` user dan tidak null atau kosong.
* Semua entitas menggunakan isolasi multi-tenant berdasarkan `company_id` untuk mencegah kebocoran data antar perusahaan.

## Tips

* Selalu gunakan FIFO batch selection untuk memastikan shelf life produk optimal di tangan partner
* Update status shipment secara real-time — partner bergantung pada informasi ini untuk perencanaan penerimaan
* Untuk batch recall, mulai dari risk assessment sebelum mengambil aksi — tidak semua isu memerlukan CRITICAL level
* Export CSV manifest secara berkala untuk audit trail dan compliance
* Gunakan internal fleet untuk area lokal guna mengontrol kualitas pengiriman langsung
* Manfaatkan field `metadata` untuk menyimpan idempotency key saat integrasi dengan API pihak ketiga
* Selalu verifikasi HACCP sebelum melepas batch untuk pengiriman — field `haccp_verified` pada LotBatch adalah gate utama
* Untuk retur, pastikan proses QC dilakukan sebelum disposisi — gunakan `quarantine_status` untuk melacak status karantina
* Monitor `expiry_alert_status` pada LotBatch secara proaktif untuk mencegah pengiriman produk mendekati kadaluarsa
* Gunakan `cost_status` pada LotBatch untuk memastikan kelengkapan pencatatan HPP sebelum shipment diinvoice ke Finance


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