Jam makan siang, meja 7 memesan tambahan dua es teh, tapi pesanan itu tidak pernah sampai ke dapur. Di meja lain, rombongan enam orang minta tagihan dipisah per orang dan kasir menghitung ulang dengan kalkulator. POS ritel biasa tidak dirancang untuk situasi seperti ini. Artikel ini membahas apa yang membedakan POS restoran, bagaimana datanya disusun, dan apa yang perlu Anda periksa sebelum memakai source code POS restoran.
Kenapa POS Ritel Tidak Cukup untuk Restoran
Di toko ritel, transaksi terjadi sekali: barang dipindai, dibayar, selesai. Di restoran, satu pesanan hidup selama tamu duduk. Pesanan dibuka, ditambah beberapa kali, dikirim ke dapur bertahap, lalu dibayar di akhir, kadang oleh beberapa orang. Jika Anda belum familiar dengan cara kerja POS secara umum, baca dulu apa itu aplikasi kasir dan cara kerjanya.
| Kebutuhan | POS ritel | POS restoran |
|---|---|---|
| Siklus transaksi | Sekali bayar | Pesanan terbuka, ditambah bertahap |
| Lokasi pelanggan | Tidak relevan | Nomor meja dan statusnya |
| Produk | SKU tetap | Menu dengan varian (level pedas, ukuran, topping) |
| Koordinasi | Hanya kasir | Pelayan, dapur, kasir |
| Pembayaran | Satu tagihan | Gabung atau pisah tagihan |
| Stok | Per barang jadi | Per bahan baku lewat resep |
Modul Inti POS Restoran
1. Manajemen menu dan varian
Menu dikelompokkan per kategori, dengan varian seperti level pedas, ukuran, atau topping tambahan. Menu yang habis harus bisa dinonaktifkan seketika agar pelayan tidak menerima pesanan yang tidak bisa dibuat.
2. Meja dan pesanan
Pelayan membuka pesanan per meja, menambah item, memindahkan tamu antarmeja, serta menggabung atau memisah tagihan. Status meja (kosong, terisi, menunggu bayar) tampil di satu layar.
3. Integrasi dapur
Item baru langsung muncul di layar dapur (kitchen display) atau tercetak di printer dapur. Ini menghapus langkah pelayan berjalan membawa kertas dan menjaga urutan pesanan.
4. Pembayaran dan pembagian tagihan
Mendukung tunai, kartu, dan QRIS, serta pemisahan tagihan per orang atau per item.
5. Laporan
Penjualan harian, menu terlaris, jam tersibuk, dan performa pelayan.
6. Stok bahan baku
Penjualan menu mengurangi stok bahan sesuai resep, sehingga Anda tahu kapan perlu belanja dan berapa bahan yang terbuang.
Desain Tabel yang Disarankan
Inti POS restoran adalah memisahkan pesanan (order) dari pembayaran (payment), karena satu pesanan bisa dibayar beberapa kali. Status per item juga dibutuhkan agar dapur tahu mana yang sudah dibuat.
CREATE TABLE dining_tables (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
code VARCHAR(10) NOT NULL UNIQUE,
status ENUM('empty','occupied','billing') DEFAULT 'empty'
);
CREATE TABLE orders (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
dining_table_id INT UNSIGNED NULL,
waiter_id BIGINT UNSIGNED NOT NULL,
status ENUM('open','closed','void') DEFAULT 'open',
opened_at DATETIME NOT NULL,
closed_at DATETIME NULL
);
CREATE TABLE order_items (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
order_id BIGINT UNSIGNED NOT NULL,
menu_id BIGINT UNSIGNED NOT NULL,
qty SMALLINT UNSIGNED NOT NULL,
unit_price DECIMAL(12,2) NOT NULL,
note VARCHAR(150) NULL,
kitchen_status ENUM('queued','cooking','served') DEFAULT 'queued',
payment_id BIGINT UNSIGNED NULL
);
CREATE TABLE payments (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
order_id BIGINT UNSIGNED NOT NULL,
method ENUM('cash','card','qris') NOT NULL,
amount DECIMAL(12,2) NOT NULL,
paid_at DATETIME NOT NULL
);
CREATE TABLE recipes (
menu_id BIGINT UNSIGNED NOT NULL,
ingredient_id BIGINT UNSIGNED NOT NULL,
qty_used DECIMAL(10,3) NOT NULL,
PRIMARY KEY (menu_id, ingredient_id)
);
Kolom payment_id di order_items memungkinkan split bill per item: setiap tamu membayar item miliknya, dan pesanan ditutup ketika semua item sudah punya pembayaran. Tabel recipes menghubungkan menu ke bahan baku.
Mengurangi stok bahan saat pesanan ditutup
Pengurangan stok sebaiknya dilakukan dalam transaksi database agar tidak setengah jalan jika terjadi error:
use Illuminate\Support\Facades\DB;
DB::transaction(function () use ($order) {
foreach ($order->items as $item) {
foreach ($item->menu->recipes as $recipe) {
Ingredient::whereKey($recipe->ingredient_id)
->decrement('stock', $recipe->qty_used * $item->qty);
}
}
$order->update(['status' => 'closed', 'closed_at' => now()]);
});
Untuk restoran ramai, pertimbangkan memindahkan perhitungan ini ke queue agar kasir tidak menunggu. Caranya dibahas di queue dan job di Laravel.
Laporan Jam Tersibuk dan Menu Terlaris
Dua laporan ini paling sering dipakai pemilik restoran untuk mengatur jadwal pegawai dan belanja bahan. Keduanya bisa diambil dari order_items dan orders yang sudah ditutup:
-- Jam tersibuk 30 hari terakhir
SELECT HOUR(o.opened_at) AS jam, COUNT(DISTINCT o.id) AS jumlah_pesanan
FROM orders o
WHERE o.status = 'closed' AND o.opened_at >= NOW() - INTERVAL 30 DAY
GROUP BY HOUR(o.opened_at)
ORDER BY jumlah_pesanan DESC;
-- Menu terlaris
SELECT m.name, SUM(oi.qty) AS terjual, SUM(oi.qty * oi.unit_price) AS omzet
FROM order_items oi
JOIN orders o ON o.id = oi.order_id AND o.status = 'closed'
JOIN menus m ON m.id = oi.menu_id
GROUP BY m.name
ORDER BY terjual DESC
LIMIT 10;
Contoh pemakaian: misalkan laporan memperlihatkan jam 15.00-17.00 hampir selalu sepi. Anda bisa memasang paket camilan sore di jam itu, lalu membandingkan angka minggu berikutnya. Menu yang terus berada di urutan bawah selama beberapa bulan layak dievaluasi: apakah harganya, porsinya, atau memang kurang diminati.
Rencana Implementasi Bertahap
- Minggu pertama: input menu, harga, dan meja. Latih pelayan membuka dan menutup pesanan.
- Minggu kedua: hubungkan dapur lewat layar atau printer. Hentikan nota kertas ke dapur.
- Minggu ketiga: aktifkan split bill dan seluruh metode pembayaran yang Anda terima.
- Bulan kedua: isi resep dan stok awal bahan, lalu cocokkan dengan stok fisik tiap minggu.
Bertahap mengurangi kebingungan staf dan memudahkan menemukan bagian yang belum berjalan.
Menjalankan Source Code POS Secara Lokal
- Siapkan PHP, Composer, dan MySQL sesuai versi yang tertulis di README proyek.
- Jalankan
composer installdi folder proyek. - Salin
.env.exampleke.env, isi koneksi database, laluphp artisan key:generate. - Jalankan migrasi dan seeder atau impor SQL bawaan.
- Jalankan
php artisan serve, login sebagai admin, lalu coba alur lengkap: buka meja, pesan, kirim ke dapur, split bill, tutup.
Jika menemui error saat instalasi, panduan menjalankan source code Laravel membahas masalah yang paling sering muncul.
Checklist Evaluasi Sebelum Memilih
- Pesanan bisa ditambah setelah dikirim ke dapur tanpa membuat pesanan baru.
- Item yang sudah dimasak tidak bisa dihapus tanpa otorisasi supervisor (mencegah kecurangan).
- Split bill per item dan per orang berjalan, totalnya tetap cocok.
- Harga di
order_itemstersimpan saat pemesanan, bukan dibaca ulang dari tabel menu. - Menu habis bisa dinonaktifkan dan langsung hilang dari layar pelayan.
- Laporan menu terlaris dan jam tersibuk tersedia atau mudah ditambahkan.
- Bisa dijalankan di tablet lewat browser tanpa instalasi khusus.
- Kode mengikuti struktur Laravel standar dan disertai dokumentasi.
Kesalahan Umum dan Solusinya
- Memakai POS ritel untuk restoran: tidak ada konsep meja, akhirnya pelayan mencatat di kertas lagi. Pilih sistem yang punya pesanan terbuka.
- Dapur tidak terhubung: pesanan tambahan sering hilang. Minimal gunakan printer dapur jika belum ada layar.
- Resep tidak diisi: modul stok bahan jadi tidak berguna. Mulai dari 10 menu terlaris dulu.
- Tidak ada pembatalan berjejak: void tanpa catatan membuka celah kecurangan. Simpan siapa, kapan, dan alasannya.
Keterbatasan Source Code Siap Pakai
Integrasi printer termal dan pembayaran digital sering bergantung pada perangkat dan penyedia yang Anda pakai, sehingga hampir selalu perlu penyesuaian. Mode offline saat internet putus juga jarang tersedia di POS berbasis web; jika lokasi Anda sering gangguan jaringan, pertimbangkan server lokal di jaringan restoran. Anda juga bertanggung jawab atas backup harian dan keamanan server.
Jika Anda sedang menimbang membeli atau membangun sendiri, panduan memilih source code siap pakai memberi kerangka pertimbangannya. Katalog GudangCode juga memuat beberapa aplikasi kasir berbasis Laravel yang bisa dijadikan bahan perbandingan.