Frontend POS adalah etalase terakhir: tampil sederhana untuk kasir, namun menghasilkan data yang kaya untuk manajemen. Target kita: cepat, akurat, terlacak. Bagian ini merinci praktik terbaik operasi kasir hingga pelaporan harian yang dapat diaudit.
1. Peran & Hak Akses Kasir
- Kasir: transaksi jual, cetak struk, tender pembayaran. Tidak boleh ubah harga.
- Supervisor: approval diskon khusus, override, void/refund, tutup shift.
- Manager: penetapan harga/promo di backend, konfigurasi pajak & metode bayar.
2. Perangkat & Konektivitas
- Terminal POS (PC/All-in-one), barcode scanner, timbangan (produk by-weight), printer struk, cash drawer, opsi customer display.
- Konektivitas stabil (LAN/Wi-Fi); pastikan sinkron data harga sebelum toko buka.
3. Alur Transaksi POS
- Login & Open Shift: input kas awal laci.
- Scan/Cari Item: barcode > cari nama/SKU; untuk by-weight, baca barcode timbangan.
- Promo Otomatis: rule dari backend berjalan tanpa input manual kasir.
- Diskon Manual (bila berhak): perlu PIN supervisor & alasan.
- Pembayaran: pilih metode (tunai/kartu/QR/e-wallet/voucher), dapat split.
- Struk: cetak/kirim e-receipt; simpan nomor struk untuk referensi refund.
- X Report (opsional): ringkas transaksi tengah hari.
- Close Shift (Z Report): hitung kas fisik vs sistem; setorkan kas.
4. Pembayaran & Split Billing
| Metode | Catatan | Rekonsiliasi |
|---|---|---|
| Tunai | Rawan selisih; wajib hitung fisik | Kas awal/akhir, setoran bank |
| Kartu (EDC) | Ikuti batch settle EDC harian | Slip EDC vs laporan POS |
| QR/E-wallet | Butuh settlement dari dashboard provider | Dashboard provider vs POS |
| Voucher/Kupon | Kedaluwarsa & syarat | Nomor seri & nilai terpakai |
| Split | Gabungan beberapa metode | Jumlahkan per metode |
5. Diskon & Override Harga
- Diskon manual butuh otorisasi; alasan wajib diisi (komplain, near-expiry, goodwill).
- Batasi besaran diskon manual per peran; audit top 10 diskon harian.
6. Refund/Return & Void
- Void sebelum pembayaran; Refund/Return setelahnya (rujuk nomor struk).
- Stok bertambah kembali hanya jika barang layak jual; bila tidak, masuk lokasi Damage.
- Setiap void/refund terekam: siapa, kapan, alasan, referensi transaksi.
7. X Report & Z Report (Open/Close Shift)
7.1. X Report (sementara)
- Ringkas transaksi s/d saat ini: omzet, jumlah transaksi, tender breakdown, diskon.
7.2. Z Report (tutup shift)
- Field minimum: kas awal, penjualan kotor, diskon, retur, pajak, penjualan bersih, tender breakdown, kas teoritis, kas fisik, over/short, setoran bank, daftar void/refund.
7.3. Rumus Over/Short
# Over/Short (selisih kas laci)
# over_short = cash_physical_end - (cash_start + cash_sales - cash_payouts - cash_refunds)
7.4. Contoh Format Z Report (CSV)
store_id,shift_id,cashier_id,open_time,close_time,cash_start,gross_sales,discount,returns,tax,net_sales,cash_sales,card_sales,qr_sales,voucher_sales,cash_payouts,cash_refunds,cash_physical_end,over_short,bank_deposit
STORE-001,SF-2025-11-23-1,USR-CA01,2025-11-23T08:00,2025-11-23T16:00,500000,12500000,350000,120000,700000,11530000,5200000,4600000,1500000,230000,120000,5705000,55000,5650000
8. Audit Trail & Anti-Fraud
- Catat peristiwa: login, open/close shift, price override, diskon manual, void/refund, perubahan metode bayar.
- Alarm dini: kasir dengan void > ambang, diskon manual sering, transaksi nol harga, transaksi dibatalkan setelah scan banyak item.
9. Dashboard KPI Harian
Contoh skema ringkas untuk gudang data POS:
-- sales_header(order_id, order_time, cashier_id, store_id, sub_total, discount, tax, total, status, shift_id, refund_of)
-- sales_lines(order_id, sku, name, category, qty, unit_price, line_discount, tax_amount)
-- payments(order_id, method, amount)
-- shifts(shift_id, store_id, cashier_id, open_time, close_time, cash_start, cash_physical_end, cash_payouts, cash_refunds)9.1. Omzet & Tender Breakdown
SELECT method, SUM(amount) AS total_amount
FROM payments
JOIN sales_header USING(order_id)
WHERE order_time::date = CURRENT_DATE AND status = 'PAID'
GROUP BY method
ORDER BY total_amount DESC;9.2. Jumlah Transaksi & Average Basket Size
-- Average Basket Size (items per transaksi) dan Average Ticket (Rp per transaksi)
WITH tx AS (
SELECT order_id
FROM sales_header
WHERE order_time::date = CURRENT_DATE AND status = 'PAID'
)
SELECT
(SELECT COUNT(*) FROM tx) AS transactions,
(SELECT SUM(total) FROM sales_header WHERE order_id IN (SELECT order_id FROM tx)) AS revenue,
(SELECT SUM(qty) FROM sales_lines WHERE order_id IN (SELECT order_id FROM tx)) AS items_sold,
(SELECT SUM(qty) FROM sales_lines WHERE order_id IN (SELECT order_id FROM tx))
/ NULLIF((SELECT COUNT(*) FROM tx),0)::numeric AS avg_basket_items,
(SELECT SUM(total) FROM sales_header WHERE order_id IN (SELECT order_id FROM tx))
/ NULLIF((SELECT COUNT(*) FROM tx),0)::numeric AS avg_ticket_value;9.3. Jam Sibuk (Hourly Heatmap)
SELECT EXTRACT(HOUR FROM order_time) AS hour, SUM(total) AS revenue, COUNT(*) AS tx
FROM sales_header
WHERE order_time::date = CURRENT_DATE AND status = 'PAID'
GROUP BY hour
ORDER BY hour;9.4. Return Rate & Nilai Refund
SELECT
COUNT(*) FILTER (WHERE refund_of IS NOT NULL) * 1.0 / NULLIF(COUNT(*),0) AS return_rate,
SUM(CASE WHEN refund_of IS NOT NULL THEN total ELSE 0 END) AS refund_value
FROM sales_header
WHERE order_time::date = CURRENT_DATE;9.5. Diskon Manual & Override
-- Asumsikan events(event_time, user_id, type, amount, order_id, reason)
SELECT user_id, COUNT(*) AS overrides, SUM(amount) AS total_override
FROM events
WHERE event_time::date = CURRENT_DATE AND type IN ('PRICE_OVERRIDE','MANUAL_DISCOUNT')
GROUP BY user_id
ORDER BY total_override DESC;9.6. Selisih Kas (Over/Short) per Shift
SELECT
s.shift_id, s.cashier_id,
(s.cash_physical_end - (s.cash_start
+ COALESCE((SELECT SUM(amount) FROM payments p JOIN sales_header h USING(order_id)
WHERE h.shift_id=s.shift_id AND p.method='CASH' AND h.status='PAID'),0)
- s.cash_payouts - s.cash_refunds)) AS over_short
FROM shifts s
ORDER BY ABS(over_short) DESC;9.7. Pajak (Summary)
SELECT l.tax_code, SUM(l.tax_amount) AS tax_collected
FROM sales_lines l
JOIN sales_header h USING(order_id)
WHERE h.order_time::date = CURRENT_DATE AND h.status='PAID'
GROUP BY l.tax_code;10. Format Ekspor Harian (CSV/JSON)
10.1. Ekspor Transaksi (CSV)
order_id,order_time,store_id,cashier_id,sku,qty,unit_price,line_discount,tax_amount,total,method
SO-2025-11-23-001,2025-11-23T09:15,STORE-001,USR-CA01,GRY-SNCK-INDO-CHIT-68G-0012,2,4900,0,196,9800,CASH
SO-2025-11-23-002,2025-11-23T09:18,STORE-001,USR-CA01,GRY-DRNK-UHT-INDO-250-0007,1,5500,500,0,5000,CARD10.2. Ekspor Z Report (JSON)
{
"store_id": "STORE-001",
"shift_id": "SF-2025-11-23-1",
"cashier_id": "USR-CA01",
"open_time": "2025-11-23T08:00",
"close_time": "2025-11-23T16:00",
"cash_start": 500000,
"gross_sales": 12500000,
"discount": 350000,
"returns": 120000,
"tax": 700000,
"net_sales": 11530000,
"tenders": {"CASH": 5200000, "CARD": 4600000, "QR": 1500000, "VOUCHER": 230000},
"cash_payouts": 120000,
"cash_refunds": 0,
"cash_physical_end": 5705000,
"over_short": 55000,
"bank_deposit": 5650000,
"voids": [{"order_id":"SO-2025-11-23-005","user":"USR-SPV1","reason":"Scan ganda"}],
"refunds": [{"order_id":"SO-2025-11-23-010","ref":"SO-2025-11-23-004","reason":"Salah ukuran"}]
}Checklist Operasional Harian
- Sebelum buka: sinkron harga/promo; uji 3 SKU acak; cek printer, scanner, laci.
- Selama operasi: pantau X report tengah hari; periksa anomali diskon/void.
- Tutup shift: Z report; hitung kas; setoran; arsip ekspor CSV/JSON; kirim dashboard KPI.
Kesimpulan
POS yang sehat berarti kasir bergerak cepat namun tetap terkendali: hak akses jelas, diskon manual terbatas, refund/void berjejak, dan Z report rapi. Dengan dashboard KPI harian dan ekspor terstruktur, manajemen bisa mengambil keputusan cepat sekaligus menjaga kepatuhan & audit.