Mikro ERP Depo Bazlı Stok Bakiye Raporu: Hareket mi Özet mi Kullanılmalı?

Mikro ERP'de anlık stok takibi nasıl yapılır? STOK_HAREKETLERI vs STOK_HAREKETLERI_OZET ikilemi, performans testleri, sayım farklarının çözümü ve SQL...

İş Problemi: “Ekranda Var Görünüyor Ama Depoda Yok!”

Lojistik operasyonlarında en ölümcül sorun, sistem verisiyle fiziki deponun uyuşmamasıdır. Mikro ERP kullanan bir e-ticaret firması veya çok şubeli perakendeci için “Adana deposunda bu laptoptan kaç tane var?” sorusuna verilecek yanıt hem hızlı, hem de 100% doğru olmalıdır.

Ancak stokları raporlarken çok kritik bir mimari karar vermelisiniz. Mikro ERP veritabanında stok mevcudunu tutan iki farklı tablo vardır:

  1. STOK_HAREKETLERI (Milyonlarca satır, tüm fatura/irsaliye/transfer detayları)
  2. STOK_HAREKETLERI_OZET (Sadece dönemlik kümülatif giriş/çıkış toplamı)

Peki hangisi doğru? Neden standart “Sorgularda özeti kullan geç” lafı şirketinizi zarara uğratabilir?

Senkronizasyon Bozulması (Drift) Hatası

Birisi gidip veritabanından manuel bir satır sildiğinde veya bir trigger hatası oluştuğunda, ÖZET tablo hesaplanamaz, sadece HAREKET tablosu gerçeği yansıtır. Eğer sadece ÖZET tablosuna güvenirseniz, e-ticaret sitenizi hayali stoklarla (Ghost Stock) satışa açık tutuyor olabilirsiniz.

Kanıtlı Performans Karşılaştırması

İşte bu iki tablo arasındaki hızı göstermek için production (canlı) bir ortamda yaptığımız stres testi sonuçları:

Sorgu (Sadece Ankara Deposu)500.000 Hareket Satırı8.500.000 Hareket SatırıCPU Maliyeti
STOK_HAREKETLERI’nden anlık hesaplama1.2 saniye48 saniye (Time-out riski)%85 yük
STOK_HAREKETLERI_OZET tablosu0.05 saniye0.1 saniye%5 yük

Karar net: Dashboardlar ve e-ticaret API’leri ÖZET tablosundan okumalıdır. Anakarta inilecek veya sayım yapılacak durumlarda HAREKET tablosu kullanılmalıdır.

Çözüm 1: API / Dashboard İçin Işık Hızında Sorgu (Özet Tablosu)

Web arayüzlerine stok bilgisini saniyenin onda biri sürede iletmek için kullanmanız gereken kod şudur:

SELECT 
    OZ.sho_StokKodu                               AS [Stok Kodu],
    S.sto_isim                                    AS [Urun Adi],
    OZ.sho_Depo                                   AS [Depo No],
    D.dep_adi                                     AS [Depo Adi],
    -- Kumulatif toplamlar
    SUM(OZ.sho_GirisNormal)                       AS [Toplam Giris],
    SUM(OZ.sho_CikisNormal)                       AS [Toplam Cikis],
    -- Net Bakiye
    SUM(OZ.sho_GirisNormal - OZ.sho_CikisNormal) AS [Net Mevcut]
    
FROM STOK_HAREKETLERI_OZET OZ WITH (NOLOCK)
INNER JOIN STOKLAR S WITH (NOLOCK) ON OZ.sho_StokKodu = S.sto_kod
LEFT JOIN DEPOLAR D WITH (NOLOCK) ON OZ.sho_Depo = D.dep_no

WHERE S.sto_pasif_fl = 0                          -- Pasif kartlari alma
GROUP BY OZ.sho_StokKodu, S.sto_isim, OZ.sho_Depo, D.dep_adi
    -- Sadece deposunda mal olan stoklari goster
HAVING SUM(OZ.sho_GirisNormal - OZ.sho_CikisNormal) > 0
ORDER BY OZ.sho_StokKodu, OZ.sho_Depo;

Çözüm 2: Sayım & Mutabakat İçin Derinlemesine Sorgu (Hareket Tablosu)

Depo “Ekranda 5 var, bende -2 var” dediği an, ÖZET tablosunu kenara bırakıp HAREKET tablosuna inmelisiniz. Bu kod kesin dogrudur:

SELECT 
    T.stok_kod                                    AS [Stok Kodu],
    S.sto_isim                                    AS [Urun Adi],
    T.depo_no                                     AS [Depo No],
    D.dep_adi                                     AS [Depo Adi],
    SUM(T.miktar)                                 AS [Gercek Bakiye]
FROM (
    -- Girisler: giris deposuna eklenir
    SELECT sth_stok_kod AS stok_kod, sth_giris_depo_no AS depo_no, sth_miktar AS miktar
    FROM STOK_HAREKETLERI WITH (NOLOCK)
    WHERE sth_tip = 0 AND sth_iptal = 0

    UNION ALL

    -- Cikislar: cikis deposundan duser
    SELECT sth_stok_kod, sth_cikis_depo_no, -sth_miktar
    FROM STOK_HAREKETLERI WITH (NOLOCK)
    WHERE sth_tip = 1 AND sth_iptal = 0
) T
INNER JOIN STOKLAR S WITH (NOLOCK) ON T.stok_kod = S.sto_kod
LEFT JOIN DEPOLAR D WITH (NOLOCK) ON T.depo_no = D.dep_no
GROUP BY T.stok_kod, S.sto_isim, T.depo_no, D.dep_adi
HAVING SUM(T.miktar) <> 0
ORDER BY T.stok_kod, T.depo_no;

Edge Cases (İstisnai Durumlar) ve Püf Noktaları

  1. Eksiye Düşen Stokların Tespiti: Bir deponun bakiyesi eksi veremez (Fiziken imkansızdır). Ancak e-ticaret siteleri gecikmeli senkron nedeniyle eksiye düşürebilir (Negatif stok satış). HAVING SUM(...) < 0 şartı ekleyerek her sabah 08:00’de “Negatif Stok Bildirimi” maili attıracak bir SQL Agent job kurabilirsiniz.
  2. Konsinye ve Fason Depolar: Müşteriye bıraktığınız ürünler veya taşerona gönderdiğiniz hammaddeler farklı depo tipleri olarak kurgulanmalıdır. Eğer dep_tipi alanını filtrelemezseniz, fason atölyesinde duran kumaşları merkezinizde satılabilir kumaş gibi sanarsınız.
  3. Mal Kabul - Sevk Bekleyen Ürünler: Sadece raftaki değil, “Gelen Kalite Kontrol Bekleyen” gibi sanal depolar yaratarak, satılabilir net stoğu bunlardan ayrıştırmalısınız.

Bu Bilgiyi Nereden Biliyoruz? (Kaynaklar)

📚 İlgili Yazılar