Mikro ERP cha_vade Alanı Nasıl Çalışır? Gerçek Vade Tarihi Hesaplama

Mikro'da vade neden bir tarih değil de sayı alanı? cha_vade ile gerçek vade hesaplama, ödeme planları ve SARGable olmayan SQL hatalarının çözümü.

İş Problemi: “Vadesi Bugün Dolan Tahsilatlar Neler?”

Haftaya başlarken Finans birimi sizden çok basit bir veri ister: “Bu ay içerisinde vadesi dolacak olan müşteri borçlarının listesini verin.” Tahsilat listesi oluşturmak için SQL’e girdiğinizde, faturanın bir “Vade Tarihi” (cha_vade_tarihi gibi) kolonu olmadığını fark eder, paniğe kapılırsınız.

Mikro’da Vade kolonu (cha_vade) bir “tarih” (datetime) değil, bir “sayı” (integer) formatındadır. Ancak bu alan iki farklı formatta veri tutabilir.

cha_vade Alanının İki Yüzü

FormatÖrnek DeğerAnlamıVade Tarihi Hesabı
Gün Sayısı30Fatura tarihinden 30 gün sonracha_tarihi + 30 gün
YYYYMMDD20261231Doğrudan 31.12.2026 tarihini temsil ederTRY_CONVERT(datetime, '20261231', 112)
Sıfır0Peşin işlem — vade = fatura tarihicha_tarihi

Bu ikili yapıyı bilmeden DATEADD(DAY, cha_vade, cha_tarihi) yazmak, 20 milyon gün eklenmesine ve datetime overflow hatasına yol açar.

Somut Hata: Raporların Patlaması

Acemice Yazılan SQL: SELECT * FROM CARI_HESAP_HAREKETLERI WHERE cha_vade = '2024-05-15' Sonuç: Conversion failed hatası. Çünkü cha_vade bir integer alanıdır.

İkinci Tuzak: DATEADD(DAY, cha_vade, cha_tarihi) Sonuç: datetime overflow hatası. Çünkü cha_vade = 20261231 değerinde 20 milyon gün eklenmeye çalışılır.

Çözüm: Güvenli Vade Tarihi Hesaplama

Aşağıdaki SQL, cha_vade alanının her iki formatını da güvenle yakalar ve overflow hatası vermez:

SELECT 
    H.cha_kod                                       AS [Cari Kodu],
    C.cari_unvan1                                   AS [Cari Unvan],
    
    CONVERT(VARCHAR(10), H.cha_tarihi, 104)         AS [Fatura Tarihi],
    H.cha_vade                                      AS [Vade Degeri],
    
    -- GUVENLI VADE TARIHI HESAPLAMASI
    CONVERT(VARCHAR(10), 
        CASE
            WHEN H.cha_vade = 0 THEN H.cha_tarihi
            WHEN H.cha_vade BETWEEN 1 AND 3650 
            THEN DATEADD(DAY, H.cha_vade, H.cha_tarihi)
            WHEN H.cha_vade BETWEEN 19000101 AND 20991231 
            THEN TRY_CONVERT(datetime, CONVERT(char(8), H.cha_vade), 112)
            ELSE H.cha_tarihi
        END, 104)                                    AS [Hesaplanan Vade Tarihi],
    
    -- Tutar
    H.cha_meblag                                    AS [Acik Borc],
    
    -- Geciken Gun Sayisi
    DATEDIFF(DAY, 
        CASE
            WHEN H.cha_vade = 0 THEN H.cha_tarihi
            WHEN H.cha_vade BETWEEN 1 AND 3650 
            THEN DATEADD(DAY, H.cha_vade, H.cha_tarihi)
            WHEN H.cha_vade BETWEEN 19000101 AND 20991231 
            THEN TRY_CONVERT(datetime, CONVERT(char(8), H.cha_vade), 112)
            ELSE H.cha_tarihi
        END, GETDATE())                              AS [Geciken Gun Sayisi],
    CASE 
        WHEN DATEDIFF(DAY, 
            CASE
                WHEN H.cha_vade = 0 THEN H.cha_tarihi
                WHEN H.cha_vade BETWEEN 1 AND 3650 
                THEN DATEADD(DAY, H.cha_vade, H.cha_tarihi)
                WHEN H.cha_vade BETWEEN 19000101 AND 20991231 
                THEN TRY_CONVERT(datetime, CONVERT(char(8), H.cha_vade), 112)
                ELSE H.cha_tarihi
            END, GETDATE()) > 30 THEN '1 Aydan Fazla Gecikme'
        WHEN DATEDIFF(DAY, 
            CASE
                WHEN H.cha_vade = 0 THEN H.cha_tarihi
                WHEN H.cha_vade BETWEEN 1 AND 3650 
                THEN DATEADD(DAY, H.cha_vade, H.cha_tarihi)
                WHEN H.cha_vade BETWEEN 19000101 AND 20991231 
                THEN TRY_CONVERT(datetime, CONVERT(char(8), H.cha_vade), 112)
                ELSE H.cha_tarihi
            END, GETDATE()) > 0 THEN 'Gecikmede'
        ELSE 'Vadesi Gelmedi'
    END                                              AS [Tahsilat Durumu]
    
FROM CARI_HESAP_HAREKETLERI H WITH (NOLOCK)
LEFT JOIN CARI_HESAPLAR C WITH (NOLOCK) ON H.cha_kod = C.cari_kod

WHERE H.cha_tip = 0                                   -- Borc (Musterinin bize borcu)
  AND H.cha_tpoz = 0                                  -- Islem Acik (Tahsil Edilmemis)
  AND H.cha_iptal = 0
ORDER BY [Hesaplanan Vade Tarihi] ASC;

Kodun Anatomisi

  • cha_vade = 0: Peşin işlem. Vade tarihi = fatura tarihi.
  • cha_vade BETWEEN 1 AND 3650: Gün sayısı formatı (1 gün - ~10 yıl). DATEADD ile güvenle hesaplanır.
  • cha_vade BETWEEN 19000101 AND 20991231: YYYYMMDD formatı. TRY_CONVERT ile datetime’a dönüştürülür.
  • ELSE cha_tarihi: Bilinmeyen format — fallback olarak fatura tarihine döner.

Performans / Ölçekleme (SARGable Sorgu Tuzağı)

Burada inanılmaz derecede önemli bir veritabanı mühendisliği kuralı vardır. “Şubat ayı içinde vadesi dolan tahsilatları getir” demek istediğinizde WHERE bloğuna şunu yazarsınız: WHERE DATEADD(DAY, H.cha_vade, H.cha_tarihi) BETWEEN '2024-02-01' AND '2024-02-28'

Bu sorgu SARGable (Search ARGument ABLE) değildir! SQL Server DATEADD fonksiyonunu kullandığınız an, tablodaki indexleri kullanamaz ve 4 Milyon satırı RAM’de tek tek hesaplayarak (Table Scan / Index Scan) tarar. AstaFlow sisteminde bu hatanın 13 saniyelik kilitlenmelere yol açtığını tespit ettik.

Çözüm? Raporları bir Computed Column (Hesaplanmış Kolon) ile Index içerisine hapsedin veya sadece filtrelenmiş bir tarih yılı (H.cha_tarihi > '2022-01-01') ile veriyi küçülttükten sonra hesaplama kullanın.

Edge Cases (İstisnai Durumlar)

Vade hesaplaması yaparken şu üç “karanlık noktayı” bilmezseniz hesaplarınız şaşar:

  1. Parçalı Taksitler (Ödeme Planları): Eğer bir faturanın vadesi 30, 60, 90 gün olarak üçe bölündüyse, Mikro cha_vade alanını kullanmaz. Bu veri, CARI_HAREKET_ODEME_VADELERI (cop_ önekiyle) tablosuna taşınır. Bu durumda faturayı baz alıp bu tablodan taksit tarihlerini JOIN etmeniz gerekir.
  2. Çek ve Senetlerin Vade Mantığı: Çek/senet hareketlerinde de vade cha_vade alanında YYYYMMDD formatında tutulur (örn: 20261231). Güvenli CASE/WHEN yapısı bu formatı da doğru yakalar. Detaylı çek/senet vade takibi için ilgili yazımıza bakın.
  3. Sıfır Vade (Peşin İşlem): cha_vade = 0 ise bu peşin faturadır, işlem tarihi neyse vade tarihi odur. Güvenli hesaplamada bu durum CASE WHEN cha_vade = 0 THEN cha_tarihi ile yakalanır.

Bu Bilgiyi Nereden Biliyoruz? (Kaynaklar)

📚 İlgili Yazılar