Gambaran Umum

Sistem Inventori adalah saraf tulang belakang dari pengelolaan operasional toko dan restoran. Fungsi utamanya adalah memastikan bahwa apa yang tercatat di dalam sistem komputer (sistem digital) selaras secara presisi dengan barang fisik yang ada di rak gudang atau di dapur. Inventori yang akurat mencegah dua mimpi buruk bisnis: kehabisan stok saat pelanggan sedang ramai memesan (Lost Sales), dan penumpukan stok berlebih yang berujung pada barang kedaluwarsa atau pemborosan (Overstock/Waste).

Bayangkan skenario di sebuah toko swalayan. Ketika sebuah botol air mineral dipindai (scan) oleh kasir dan transaksi selesai dibayar, secara magis angka ketersediaan air mineral tersebut di database berkurang satu. Namun, dalam bisnis F&B seperti restoran Nasi Goreng, logikanya jauh lebih kompleks. Pemilik restoran tidak membeli “Nasi Goreng” dalam bentuk jadi dari pemasok. Mereka membeli Beras dalam hitungan karung (Kilogram), Telur per papan (Pcs), dan Minyak per jerigen (Liter). Fitur “Resep” (Recipe) dalam modul inventori ini bertugas menjembatani perbedaan antara produk yang “Dijual” dengan bahan baku yang “Dibeli”.

Dengan fitur Kartu Stok (Stock Card), pemilik bisnis memiliki jejak audit yang mutlak. Layaknya rekening koran di bank, kartu stok mencatat detik demi detik kapan barang masuk (dari supplier), kapan barang keluar (terjual), hingga penyesuaian darurat (barang pecah atau rusak), sehingga setiap pergerakan barang dapat dipertanggungjawabkan.

Alur Kerja

Terdapat dua mode alur kerja utama dalam sistem inventori Temuya POS: Mode Ritel Sederhana (Barang Jadi) dan Mode Manufaktur F&B (Resep).

Skenario 1: Mode Barang Jadi (Ritel) Pengelola toko sepatu mendaftarkan “Sepatu Kets Hitam Ukuran 40”. Mereka menerima pengiriman dari supplier sebanyak 50 pasang. Mereka masuk ke modul Inventori dan membuat dokumen “Barang Masuk” (Goods Receipt), lalu memasukkan kuantitas +50. Sekarang stok tercatat 50. Sepanjang hari, kasir menjual total 3 pasang sepatu. Sistem secara real-time mencatat transaksi keluar di kartu stok: -1 (09:00), -1 (11:30), -1 (15:00). Pada sore hari, sisa stok yang terlihat di sistem secara otomatis adalah 47 pasang.

Skenario 2: Mode Resep (Bisnis F&B) Pemilik kedai ramen mendaftarkan menu “Ramen Spesial”. Menu ini tidak dihitung stoknya secara langsung (karena dibuat sesuai pesanan / made to order). Sebagai gantinya, pemilik mendefinisikan Resep / Bill of Materials (BOM) untuk menu ini di dashboard. 1 porsi “Ramen Spesial” =

  • Bahan Baku: Mie Ramen basah (mengurangi stok 150 Gram)
  • Bahan Baku: Kuah Kaldu (mengurangi stok 200 ml)
  • Bahan Baku: Telur Rebus (mengurangi stok 0.5 Butir)

Saat pembeli memesan 2 porsi Ramen Spesial di kasir, sistem inventori tidak memotong stok ‘Ramen’, melainkan menjalankan background job yang menghitung multiplikasi resep. Sistem akan otomatis memotong: 300 Gram Mie, 400 ml Kaldu, dan 1 Telur dari gudang bahan baku utama. Jika stok mie di gudang sudah turun menyentuh “Batas Minimum” (misal: sisa 5 kg), sistem akan mengirimkan notifikasi peringatan (Alert) ke HP manajer bahwa persediaan kritis dan saatnya menelepon pemasok.

flowchart TD
    A[Mulai: Transaksi Kasir Dibayar] --> B{Cek Tipe Produk}
    
    B -- Barang Jadi (Retail) --> C[Kurangi Stok Produk Jadi]
    C --> D[Catat ke Kartu Stok: Tipe 'Penjualan']
    
    B -- Barang Resep (F&B) --> E[Ambil Data Resep/BOM dari Database]
    E --> F[Kalkulasi: Kuantitas Jual * Takaran Resep Tiap Bahan]
    
    F --> G[Loop Tiap Bahan Baku]
    G --> H[Kurangi Stok Bahan Baku di Gudang]
    H --> I[Catat ke Kartu Stok Bahan Baku: Tipe 'Pemakaian Resep']
    
    D --> J[Cek Stok Sisa Setelah Berkurang]
    I --> J
    
    J --> K{Sisa < Batas Minimum?}
    K -- Ya --> L[Kirim Notifikasi Peringatan Stok Rendah]
    K -- Tidak --> M[Selesai]

Teknologi & Infrastruktur

Modul inventori adalah salah satu bagian paling krusial dan padat proses dalam arsitektur backend kita. Pergerakan stok adalah transaksi finansial yang tidak boleh gagal atau ganda (double deduction). Oleh karena itu, semua pengurangan stok akibat penjualan diikat dalam satu Database Transaction SQL bersamaan dengan pembayaran kasir. Jika perhitungan resep gagal di tengah jalan, seluruh transaksi kasir digagalkan (rollback) untuk menjaga integritas data.

Kartu Stok diimplementasikan dalam pola desain sistem akuntansi (Ledger). Daripada hanya memiliki satu kolom tabel current_stock di tabel produk (yang rawan rusak tanpa jejak), kita memiliki tabel stock_ledgers yang mencatat setiap delta perubahan (+10, -2, -5). Kolom current_stock yang dilihat pengguna hanyalah agregasi (SUM) dari seluruh riwayat ledger tersebut. Walaupun kita menyimpan current_stock untuk kecepatan baca (caching), sumber kebenaran mutlaknya (Single Source of Truth) adalah tabel riwayat ledger.

Penanganan multi-satuan ukur (Unit of Measurement/UoM) ditangani melalui konversi. Misalnya, pembelian dari supplier adalah 1 Karung (25 Kg), tetapi resep memotong dalam satuan Gram. Sistem menyimpan multiplier konversi standar di tabel UoM, sehingga semua perhitungan stok di backend dibakukan ke dalam satuan terkecil penyusunnya (dalam hal ini, gram).

Tabel Database Terkait

Nama TabelDeskripsiKolom Penting
inventory_itemsMaster data barang yang dihitung stoknya (bahan baku maupun barang jadi).id, name, sku, uom_id, minimum_stock_alert, current_stock_cached
product_recipesRelasi produk jual ke komponen bahan baku (BOM).id, product_id, inventory_item_id, quantity_required (takaran)
stock_ledgersKartu stok, buku besar riwayat pergerakan keluar-masuk.id, inventory_item_id, transaction_type (IN/OUT/SALE), quantity_change, reference_id (nomor nota)

Endpoint API

MetodeEndpointFungsi dan Kegunaan
GET/api/v1/inventoryMembaca daftar stok barang saat ini beserta peringatan batas kritis.
GET/api/v1/inventory/:item_id/ledgerMengambil data riwayat mutasi / kartu stok sebuah barang spesifik pada rentang tanggal tertentu.
POST/api/v1/inventory/adjustEndpoint manual untuk penyesuaian stok darurat (misal menambah/mengurangi manual).
POST/api/v1/products/:id/recipesMendaftarkan struktur resep bahan baku pembentuk suatu produk jual.

Keterkaitan dengan Fitur Lain

  1. Modul Pembelian (Purchase Order): Stok paling banyak ditambahkan (In) dari fitur pesanan pembelian ke pemasok. Ketika dokumen “Barang Diterima” diverifikasi, ia memicu event penambahan kuantitas ke tabel inventori.
  2. Manajemen Varian & Modifier: Varian (misal ukuran L) memiliki SKU stok sendiri. Modifier juga bisa dilingkarkan ke resep (misal: modifier “Ekstra Boba” memiliki resep memotong 50 gram boba mentah).
  3. Laporan Laba Rugi (Profit & Loss): Nilai valuasi barang di inventori (Total nilai aset gudang) secara dinamis memengaruhi kalkulasi beban pokok penjualan (COGS), yang menjadi dasar perhitungan laporan keuntungan bersih perusahaan di akhir bulan.

Hal Penting yang Perlu Diketahui

  • Pencegahan Stok Negatif: Secara default, sistem tidak akan mengizinkan kasir menjual barang fisik yang stoknya nol di database, untuk mencegah kebingungan akuntansi (Stok bernilai -5). Namun, kita menyediakan opsi konfigurasi “Izinkan Over-selling” khusus untuk kasus darurat di mana kasir tahu fisik barang ada di depan mata namun admin lupa melakukan entri data masuk di komputer.
  • Kalkulasi Batch & Antrean (Queue): Pada jam sibuk (rush hour) di mana terjadi 500 transaksi per menit, perhitungan pemotongan ratusan resep bahan baku secara berbarengan dapat menyebabkan database deadlock/locking. Untuk skala enterprise, pemotongan stok bahan baku via resep didelegasikan ke message broker (seperti RabbitMQ atau Redis Queue) agar diproses di latar belakang secara berurutan dan aman, tanpa memperlambat layar aplikasi kasir.
erDiagram
    PRODUCTS ||--o{ PRODUCT_RECIPES : "dibuat menggunakan"
    PRODUCT_RECIPES }o--|| INVENTORY_ITEMS : "membutuhkan bahan baku"
    INVENTORY_ITEMS ||--o{ STOCK_LEDGERS : "memiliki riwayat mutasi"
    
    PRODUCTS {
        string id PK
        string name "Menu (ex: Nasi Goreng)"
    }
    
    INVENTORY_ITEMS {
        string id PK
        string name "Bahan (ex: Beras Karung)"
        string uom "Satuan Dasar (ex: Gram)"
        int current_stock
    }
    
    PRODUCT_RECIPES {
        string product_id FK
        string inventory_item_id FK
        decimal qty_required "Takaran (ex: 150 gr)"
    }
    
    STOCK_LEDGERS {
        string id PK
        string inventory_item_id FK
        string trans_type "IN / OUT"
        decimal quantity_change "ex: -150"
        datetime created_at
    }