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ğer | Anlamı | Vade Tarihi Hesabı |
|---|---|---|---|
| Gün Sayısı | 30 | Fatura tarihinden 30 gün sonra | cha_tarihi + 30 gün |
| YYYYMMDD | 20261231 | Doğrudan 31.12.2026 tarihini temsil eder | TRY_CONVERT(datetime, '20261231', 112) |
| Sıfır | 0 | Peşin işlem — vade = fatura tarihi | cha_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 failedhatası. Çünkücha_vadebir integer alanıdır.
İkinci Tuzak:
DATEADD(DAY, cha_vade, cha_tarihi)Sonuç:datetime overflowhatası. Çünkücha_vade = 20261231değ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).DATEADDile güvenle hesaplanır.cha_vade BETWEEN 19000101 AND 20991231: YYYYMMDD formatı.TRY_CONVERTile 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:
- Parçalı Taksitler (Ödeme Planları): Eğer bir faturanın vadesi 30, 60, 90 gün olarak üçe bölündüyse, Mikro
cha_vadealanı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. - Çek ve Senetlerin Vade Mantığı: Çek/senet hareketlerinde de vade
cha_vadealanı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. - Sıfır Vade (Peşin İşlem):
cha_vade = 0ise bu peşin faturadır, işlem tarihi neyse vade tarihi odur. Güvenli hesaplamada bu durumCASE WHEN cha_vade = 0 THEN cha_tarihiile yakalanır.
Bu Bilgiyi Nereden Biliyoruz? (Kaynaklar)
- AstaFlow Case Study: Finansal Tahsilat Akışları ve Yaşlandırma Modülleri
- Mikro ERP DB API: CARI_HAREKET_ODEME_VADELERI Tablo Detayları
- İlgili Çözüm: Cari Yaşlandırma (Aging) Optimizasyonu