Mikro ERP Banka Hesap Hareketleri ve Bakiye Raporu SQL Sorgusu

Mikro ERP'de banka hesapları nasıl yorumlanır? CARI_HESAP_HAREKETLERI içindeki banka işlemleri, POS bloke çözümleri, gecelik repolar ve tam kapsamlı...

İş Problemi: “Dün Yatan Para Neden Bakiyede Yok?”

Mikro ERP mimarisinde “Banka” diye ayrı bir fiziki tablo yoktur. Tüm müşteri, tedarikçi, kasa ve banka işlemleri devasa bir tablo olan CARI_HESAP_HAREKETLERI tablosunda saklanır.

Finans müdürü “Hesaplarımızda anlık ne kadar var?” diye sorduğunda standart bir cari rapor çekmek felaketle sonuçlanır. Dahası, işletmelerin en çok düştüğü iki kör nokta vardır:

  1. POS Blokesindeki Paralar: Müşteri kredi kartıyla ödemiştir, fiş kesilmiştir (cari borcu kapanmıştır) ancak para bankanın ertesi gün (veya 30 gün) blokesindedir. Bu para banka hareketlerinde var görünse de kullanılamaz.
  2. Kasa / Banka Karışıklığı: Tahsilat elemanı parayı bankadan çektiğinde fiş yanlış işlenirse kasadaki para bankada, bankadaki para kasada görünür.

Eğer SQL filtrelerinizi doğru (cha_cari_cins) dizmezseniz, şirketin nakit pozisyonunu haftalarca yanlış yorumlarsınız.

Beklenen Output ve Hata Tespiti

Aşağıdaki doğru sorgu yapısı kullanılmadığında karşılaşabileceğiniz yanıltıcı tablo:

Hatalı Yorumlama Örneği: Akbank Hesabı Toplam Bakiye: 1.500.000 TL Arka Plandaki Gerçek: 500.000 TL’si 30 gün vadeli kredi kartı blokajında, kullanılabilir nakit sadece 1.000.000 TL’dir!

Çözüm: Anlık Durum ve Bloke Farkındalıklı Sorgu

Tüm banka hesaplarının sadece kümülatif nakit durumunu değil, vadeli POS bloke detaylarını da ayrıştıran SQL kurgusu şöyledir:

SELECT 
    H.cha_kod                                      AS [Banka Cari Kodu],
    ISNULL(B.ban_ismi + ' - ' + B.ban_sube, H.cha_kod) AS [Banka / Şube Adı],
    CASE H.cha_d_cins
        WHEN 0 THEN 'TL' WHEN 1 THEN 'USD' WHEN 2 THEN 'EUR'
        ELSE 'Döviz: ' + CAST(H.cha_d_cins AS VARCHAR)
    END                                            AS [Döviz Cinsi],
    
    -- Kümülatif TOPLAM Bakiye
    SUM(CASE WHEN H.cha_tip = 0 THEN H.cha_meblag ELSE -H.cha_meblag END) AS [Toplam Bakiye],
    
    -- POS veya vadeli işlemler için blokesi çözülmemiş miktar
    SUM(CASE WHEN H.cha_tip = 0 
                  AND CASE
                        WHEN H.cha_vade BETWEEN 19000101 AND 20991231 
                        THEN TRY_CONVERT(datetime, CONVERT(char(8), H.cha_vade), 112)
                        WHEN H.cha_vade BETWEEN 1 AND 3650 
                        THEN DATEADD(DAY, H.cha_vade, H.cha_tarihi)
                        ELSE NULL
                      END > GETDATE()
                  AND H.cha_evrak_tip = 1 -- Tahsilat fişi / POS
             THEN H.cha_meblag ELSE 0 END)          AS [POS Blokesindeki Tutar],
             
    -- KULLANILABİLİR GERÇEK NAKİT = Toplam - Blokedeki
    SUM(CASE WHEN H.cha_tip = 0 THEN H.cha_meblag ELSE -H.cha_meblag END) -
    SUM(CASE WHEN H.cha_tip = 0 
                  AND CASE
                        WHEN H.cha_vade BETWEEN 19000101 AND 20991231 
                        THEN TRY_CONVERT(datetime, CONVERT(char(8), H.cha_vade), 112)
                        WHEN H.cha_vade BETWEEN 1 AND 3650 
                        THEN DATEADD(DAY, H.cha_vade, H.cha_tarihi)
                        ELSE NULL
                      END > GETDATE()
                  AND H.cha_evrak_tip = 1 
             THEN H.cha_meblag ELSE 0 END)          AS [Kullanılabilir Nakit Bakiye]

FROM CARI_HESAP_HAREKETLERI H WITH (NOLOCK)
LEFT JOIN BANKALAR B WITH (NOLOCK) ON H.cha_kod = B.ban_kod

WHERE H.cha_iptal = 0
  -- EN KRİTİK FİLTRE: 2 = Banka Cinsi
  AND H.cha_cari_cins = 2                          

GROUP BY H.cha_kod, B.ban_ismi, B.ban_sube, H.cha_d_cins
HAVING SUM(CASE WHEN H.cha_tip = 0 THEN H.cha_meblag ELSE -H.cha_meblag END) <> 0
ORDER BY [Kullanılabilir Nakit Bakiye] DESC;

Kodun Anatomisi

  • cha_cari_cins = 2: Mikro mimarisinde 0 = Müşteri/Tedarikçi, 2 = Banka, 4 = Kasa temsilidir. Bankaları ayırmak için bu zorunludur.
  • LEFT JOIN BANKALAR: Banka bilgileri CARI_HESAPLAR tablosunda değil, BANKALAR tablosunda tutulur (ban_kod, ban_ismi, ban_sube). Bu ayrım Mikro’nun en sık gözden kaçan mimari detaylarından biridir.
  • Vade Hesabı (cha_vade): Mikro’da cha_vade alanı bazen tarih formatında integer (örn: 20240315), bazen gün sayısı (örn: 30) tutar. Doğrudan DATEADD(DAY, cha_vade, cha_tarihi) yazmak 20 milyon gün eklenmesine ve datetime overflow hatasına yol açar. CASE WHEN ... BETWEEN 19000101 AND 20991231 yapısı her iki formatı da güvenle yakalar.

Performans / Ölçekleme Testi

AstaFlow platformunda 40 Milyondan fazla cari hareketi olan bir holding veritabanında test edilmiştir. Banka hareketi sayısı spesifik olarak az olduğundan (cha_cari_cins = 2 selectivity oranı düşüktür), sorgu Execution Plan tarafında zorlanmaz. Ancak bu raporda cha_cari_cins filtreleri tek başına bir index’e sahip olmadığı için Clustered Index Scan yapabilir. Optimizasyon Notu: Çok yoğun sunucularda (cha_cari_cins, cha_iptal) için bir Non-Clustered Index yaratmak sorguyu ~2.5 saniyeden 0.1 saniyeye indirmiştir.

Edge Cases (İstisnai Durumlar)

Daha ileri düzey analizler için dikkat edilmesi gereken “kırılma” noktaları:

  1. Kur Farkı Düzenleme Fişleri: Yıl sonunda veya ay sonunda TL bakiye ile Döviz bakiyeyi dengelemek için program kur farkı fişleri (cha_evrak_tip = 59) keser. Eğer bu fişleri dışlamazsanız, gün boyunca bankaya nakit para “girmiş” sanabilirsiniz. Nakit akışına sadece fiili ödeme/tahsilat dahil edilmelidir.
  2. Posta Çeki Hesapları: Banka sayılan ama PTT üzerinden yürüyen posta çeki hesapları bazen cha_cari_cins = 4 (Kasa) olarak kurgulanabilir. İşletmenin kurulum standardına dikkat edin.
  3. Müşteri Çeki Teminatı: Müşterinin size verdiği çeki bankaya “Teminata” gönderdiğinizde bu bankanın bakiyesini artırmaz. Ne zaman çek tahsil edildi, o zaman banka hareketlerine yansır.

Bu Bilgiyi Nereden Biliyoruz? (Kaynaklar)

📚 İlgili Yazılar