Projeler

Barkodlu Depo ve Kasa Programı

Bir iletişim bayisi için yazdığım depo, kasa ve raporlama programı: kameradan barkod okuyup sepete ekliyor, stoktan düşüyor, günlük kâr ve kasayı hesaplıyor. Bilgisayarda da telefonda da çalışıyor.

Tarih
Son güncelleme
Rolüm
Ürün tasarımı + geliştirme
Durum
Tamamlandı
Teknolojiler
Node.js · JavaScript · WebAssembly

Amaç

Bir telefon ve iletişim bayisinin stok ve satışını barkodla takip etmek: hangi üründen kaç tane kaldı, ürün kaça geldi, gün sonunda kasa tutuyor mu? İhtiyaç basitti: ürünün arkasındaki barkodu okut, ürün bilgisi gelsin, satınca stoktan düşsün.

Neler yapıyor?

  • Kasa: Barkod okutunca ürün sepete giriyor. Nakit, kart veya karma ödeme, para üstü hesabı ve yazdırılabilir fiş var.
  • Stok girişi: Ürünlerin arkasındaki barkodları tek tek okutarak depoya alıyorum. Bir ürün seçip ardından gelen tüm tanımsız barkodları ona bağlamak mümkün; 10 ekran koruyucunun 10 farklı barkodu olsa bile arka arkaya okutmak yeterli.
  • Barkod üretimi: Ürün adını yazınca (ör. "iphone") model önerileri geliyor. Barkod otomatik üretilip ürün adıyla birlikte küçük etiket olarak basılıyor.
  • İade ve iptal: Satış kalem kalem iade ediliyor, ürün stoğa geri dönüyor.
  • Hizmet kalemleri: Hat satışı, fatura ödeme, TL yükleme gibi stoksuz işlemler komisyonuyla birlikte kâra yansıyor.
  • Raporlar: Günlük ciro, maliyet, net kâr, kasadaki nakit, personel ve ürün dökümü. Kapanış raporu yazdırılıyor, satışlar Excel'e aktarılıyor.
  • Personel girişi: Çalışanlar kendi şifresiyle giriyor; maliyet ve kâr bilgisini göremiyor, iade ve raporlara erişemiyor.
  • Sayım modu: Rafı okutarak sayıyorum, sistem stoğuyla farkı çıkarıyor.

Demo

Program bir işletmenin kendi bilgisayarında çalışıyor, bu yüzden indirmeye ya da canlı siteye açık değil. Aşağıdaki görüntüler, programın güncel sürümünün uydurma ürün ve satış verileriyle çalıştırılmasıyla alındı; gerçek işletme verisi içermiyor.

Ana sayfa: günlük ciro, maliyet, net kâr ve son 14 günün grafiği.

Ana sayfa: ciro, net kâr, kâr oranı, son 14 gün grafiği ve en çok satılanlar

Kasa: barkod okutunca ürün sepete giriyor; nakit, kart ya da karma ödeme.

Kasa: sepet, adet ve fiyat düzenleme, nakit/kart/karma ödeme düğmeleri

Ürünler: barkod, maliyet, satış fiyatı ve stok durumu; azalan stok işaretli.

Ürünler: stok maliyeti, satış değeri, ürün listesi ve stok işlemleri

Raporlar: günlük kapanış, kasada olması gereken nakit ve kart tahsilatı.

Raporlar: satış özeti, kasa ve kapanış hesabı

Nasıl çalışıyor?

Programın sunucusu tek bir Node.js dosyası. Veritabanı yerine data/db.json dosyası kullanıyor; her yazma önce geçici dosyaya yapılıp yeniden adlandırıldığı için yarım kalan bir yazma veriyi bozmuyor. Her gün otomatik yedek alınıyor.

Asıl dikkat isteyen kısım ürün ile barkodun ayrılması oldu. Her ürünün aynı barkodu taşımıyor: bazı ürünlerde tüm parçalar aynı barkoda sahip, bazılarında her parçanın barkodu farklı. Bu yüzden veri modeli iki parça:

// products: ürün kartı (ad, fiyat, toplam stok)
// codes:    barkod -> hangi ürüne ait, bu barkodla kaç adet stokta
{
  products: { P00003: { name: "iPhone 15 Cam Ekran Koruyucu", stock: 5 } },
  codes: {
    NA00001001: { productId: "P00003", count: 1 },
    NA00001002: { productId: "P00003", count: 0 }, // satıldı
  },
}

Böylece aynı barkodlu ürünler adet adet düşüyor; ayrı barkodlu parçalar ise bir kez satılınca o barkod "satıldı" oluyor ve yanlışlıkla ikinci kez satılamıyor.

Barkodu kamerayla okumak

İlk sürümde hazır bir kütüphane kullandım ama okumada zorlandı. Sonra kendi döngümü yazdım:

  • Kamera 1080p ve sürekli netleme ile açılıyor, kadrajın tamamı taranıyor.
  • Tarayıcıda yerleşik BarcodeDetector varsa (Android Chrome) o kullanılıyor. Yoksa ZXing'in WebAssembly sürümü, bir Web Worker içinde çalışıyor; bu sayede çözme işi ekranı dondurmuyor.
  • Yanlış okumaya karşı: EAN gibi sağlama toplamlı barkodlar tek okumada kabul ediliyor, Code128 gibi türlerde art arda iki okuma bekleniyor.
  • USB barkod okuyucular klavye gibi yazdığı için, odak bir butondayken gelen Enter'ın "Öde" gibi bir düğmeyi tetiklemesini de ayrıca engelledim.

Telefonda kamera

Tarayıcılar kamerayı yalnızca HTTPS'te açıyor. Sunucu ilk çalıştırmada kendinden imzalı bir sertifika üretip hem localhost hem de ağ adresinde HTTPS sunuyor; Ayarlar sayfasındaki QR kodu telefonla okutunca program telefonda açılıyor.

Öğrendiklerim

  • Veri modelini erken doğru kurmak: "Ürün = barkod" diye başlamıştım; gerçek hayatta bir ürünün birden çok barkodu olabildiği ortaya çıkınca modeli ikiye ayırmam gerekti. Eski verinin otomatik taşınması için bir geçiş kodu yazmak da şart oldu.
  • Para hesabında "olay" mantığı: Geçmiş bir satışın iadesi, iadenin yapıldığı günün kasasına yazılmalı. Gelir ve kârı satış ve iade olayları üzerinden hesaplayınca raporlar tutarlı çıktı.
  • Yetkiyi sunucuda uygulamak: Personelin maliyeti görmemesi için arayüzde bir alanı gizlemek yetmez; sunucu zaten o veriyi hiç göndermemeli.