Erp Asistanı Erp Asistanı
Mikro SQL

Mikro Cari Yaşlandırma Raporu SQL: 30/60/90 Gün Vade Analizi

Mikro'da vadesi geçen alacaklar, 30/60/90 gün yaşlandırma matrisi ve cari gecikme dökümü hangi SQL ile alınır? cha_vade'nin ikili anlamı, fn_OpVadeTarih ile doğru vade hesabı ve sık hatalar. Gerçek v16 DB'de test edildi, v17'de doğrulandı.

Erp Asistanı Erp Asistanı Editör ekibi 6 dk okuma
Mikro Cari Yaşlandırma Raporu SQL: 30/60/90 Gün Vade Analizi

"Kimden ne kadar alacağım var, ne kadarının vadesi geçti, kaç gündür bekliyor?" Tahsilat takibinin bu üç sorusu tek raporda birleşir: cari yaşlandırma (aging). Mikro'da bu raporu doğru kurmanın anahtarı, vade tarihinin nerede saklandığını bilmektir — çünkü CARI_HESAP_HAREKETLERI tablosunda hazır bir "vade tarihi" kolonu yoktur. Bu yazıdaki tüm sorgular gerçek bir Mikro v16 veritabanında çalıştırıldı, v17'de de doğrulandı.

Vade tarihi hangi kolonda? (Cevap: hiçbirinde)

Mikro, vadeyi cha_vade kolonunda iki farklı anlamda tutar:

cha_vade değeri Anlamı
0 veya negatif Gün sayısı: vade tarihi = cha_tarihi + ABS(cha_vade) gün (0 = peşin)
Pozitif Ödeme planı numarası (ODEME_PLANLARI tablosuna işaret eder)

Bu ikili yapıyı elle çözmeye çalışmayın; Mikro'nun kendi fonksiyonu ikisini de doğru hesaplar:

-- Her hareketin gerçek vade tarihi
SELECT TOP 20 cha_kod, cha_tarihi, cha_vade,
       dbo.fn_OpVadeTarih(cha_vade, cha_tarihi) AS [Vade Tarihi]
FROM CARI_HESAP_HAREKETLERI
WHERE cha_iptal = 0
ORDER BY cha_tarihi DESC;

fn_OpVadeTarih, cha_vade bir ödeme planıysa planın taksit yapısından, gün sayısıysa doğrudan ekleyerek vade tarihini döndürür. Kolon NULL gelebilir; sorgularda ISNULL(cha_vade, 0) ile peşin kabul etmek en güvenlisidir.

Vadesi geçen alacaklar listesi

En sık ihtiyaç duyulan hâli: bugün itibarıyla vadesi geçmiş net bakiyesi olan cariler.

SELECT ch.cha_kod AS [Cari Kod], c.cari_unvan1 AS [Ünvan],
       SUM(CASE WHEN ch.cha_tip = 0 THEN ch.cha_meblag ELSE -ch.cha_meblag END) AS [Vadesi Geçen]
FROM CARI_HESAP_HAREKETLERI ch
JOIN CARI_HESAPLAR c ON c.cari_kod = ch.cha_kod
WHERE ch.cha_iptal = 0
  AND dbo.fn_OpVadeTarih(ISNULL(ch.cha_vade, 0), ch.cha_tarihi) < CAST(GETDATE() AS date)
GROUP BY ch.cha_kod, c.cari_unvan1
HAVING SUM(CASE WHEN ch.cha_tip = 0 THEN ch.cha_meblag ELSE -ch.cha_meblag END) > 0
ORDER BY [Vadesi Geçen] DESC;

İki kritik ayrıntı: cha_tip yönü (0 = borç, 1 = alacak; müşteri bakiyesi borç − alacak farkıdır) ve cha_iptal = 0 filtresi. İkisinden biri eksikse rapor "doğru görünüp" yanlış olur.

30/60/90 gün yaşlandırma matrisi

Yaşlandırmanın klasiği: her carinin bakiyesini gecikme kovalarına dağıtmak. CROSS APPLY ile gecikme gününü ve hareket yönünü bir kez hesaplayıp tüm kovalarda kullanıyoruz — hem okunur hem hızlıdır:

SELECT ch.cha_kod AS [Cari Kod], c.cari_unvan1 AS [Ünvan],
       SUM(x.net) AS [Bakiye],
       SUM(CASE WHEN x.gecikme <= 0              THEN x.net ELSE 0 END) AS [Vadesi Gelmemiş],
       SUM(CASE WHEN x.gecikme BETWEEN 1 AND 30  THEN x.net ELSE 0 END) AS [1-30 Gün],
       SUM(CASE WHEN x.gecikme BETWEEN 31 AND 60 THEN x.net ELSE 0 END) AS [31-60 Gün],
       SUM(CASE WHEN x.gecikme BETWEEN 61 AND 90 THEN x.net ELSE 0 END) AS [61-90 Gün],
       SUM(CASE WHEN x.gecikme > 90              THEN x.net ELSE 0 END) AS [90+ Gün]
FROM CARI_HESAP_HAREKETLERI ch
JOIN CARI_HESAPLAR c ON c.cari_kod = ch.cha_kod
CROSS APPLY (SELECT
    DATEDIFF(day, dbo.fn_OpVadeTarih(ISNULL(ch.cha_vade, 0), ch.cha_tarihi),
             CAST(GETDATE() AS date)) AS gecikme,
    CASE WHEN ch.cha_tip = 0 THEN ch.cha_meblag ELSE -ch.cha_meblag END AS net) x
WHERE ch.cha_iptal = 0
GROUP BY ch.cha_kod, c.cari_unvan1
HAVING SUM(x.net) <> 0
ORDER BY [Bakiye] DESC;

Kovaların toplamı her satırda Bakiye kolonuna eşittir — raporunuzu bu eşitlikle test edin; tutmuyorsa bir filtre kaçırmışsınız demektir (en sık suçlu NULL vade).

Tek carinin gecikme dökümü

Telefon açmadan önce elinizde olsun: hangi evrak, kaç gündür gecikmiş?

SELECT ch.cha_tarihi AS [Tarih],
       ch.cha_evrakno_seri + '-' + CAST(ch.cha_evrakno_sira AS varchar(12)) AS [Evrak],
       dbo.fn_OpVadeTarih(ISNULL(ch.cha_vade, 0), ch.cha_tarihi) AS [Vade],
       DATEDIFF(day, dbo.fn_OpVadeTarih(ISNULL(ch.cha_vade, 0), ch.cha_tarihi),
                CAST(GETDATE() AS date)) AS [Gecikme (gün)],
       CASE WHEN ch.cha_tip = 0 THEN ch.cha_meblag ELSE -ch.cha_meblag END AS [Tutar]
FROM CARI_HESAP_HAREKETLERI ch
WHERE ch.cha_iptal = 0 AND ch.cha_kod = '120-001'
ORDER BY [Vade];

Bilmeniz gereken sınır: hareket bazlı yaklaşım

Bu sorgular hareket bazlı yaşlandırma yapar: vadesi geçen borç hareketlerinden alacak hareketlerini net düşer. Kapama/eşleştirme (hangi tahsilat hangi faturayı kapattı) kullanan işletmelerde kuruş hassasiyetli "açık kalem" takibi için Mikro'nun kapama kayıtlarını da hesaba katmak gerekir. Pratikte çoğu KOBİ'nin tahsilat toplantısı için hareket bazlı matris fazlasıyla yeterlidir; iki yöntem arasındaki fark, kapatılmamış eski alacak ile yeni tahsilatın hangi kovada netleştiğidir.

Sık yapılan hatalar

  • cha_vade'yi doğrudan gün sanmak. Pozitif değer ödeme planı numarasıdır; 30 yazan kayıt "30 gün" değil "30 numaralı plan" olabilir. Daima fn_OpVadeTarih kullanın.
  • cha_tip yönünü ters almak. 0 = borç, 1 = alacak. Ters işaret, alacaklıyı borçlu gösterir.
  • cha_iptal = 0 filtresini unutmak. İptal edilen evraklar tabloda durur; filtresiz rapora karışır.
  • NULL vadeyi ele almamak. NULL < GETDATE() false döner, satır sessizce rapor dışı kalır; ISNULL(cha_vade, 0) ile peşin sayın.
  • Evrak tarihi ile vade tarihini karıştırmak. Yaşlandırma cha_tarihi'ne değil vade tarihine göre yapılır; 90 gün vadeli dünkü fatura "vadesi gelmemiş" kovasındadır.

Sık sorulanlar

Mikro'da vade tarihi hangi tabloda tutulur? Ayrı bir kolon yoktur: CARI_HESAP_HAREKETLERI.cha_vade gün sayısını ya da ödeme planı numarasını tutar; gerçek vade tarihi dbo.fn_OpVadeTarih(cha_vade, cha_tarihi) ile hesaplanır.

Bu sorgular v16 ve v17'de aynı mı çalışır? Evet. Kullanılan kolonlar (cha_tip, cha_meblag, cha_vade, cha_iptal) ve fn_OpVadeTarih iki sürümde de aynıdır; sorgular v16'da gerçek veriyle, v17'de derleme doğrulamasıyla test edildi.

Ortalama tahsilat vadesini de hesaplayabilir miyim? Evet: aynı CROSS APPLY deseninde gecikme gününü tutarla ağırlıklandırıp (SUM(gecikme * net) / NULLIF(SUM(net), 0)) cari başına ağırlıklı ortalama gecikme elde edersiniz.

Yürüyen bakiyeli ekstreyi de aynı tablodan mı alırım? Evet, kaynak yine CARI_HESAP_HAREKETLERI'dir ama window fonksiyonlu ayrı bir sorgu gerekir: Mikro cari ekstre ve bakiye raporu yazısında hazır.


Yaşlandırma raporu her şirkette biraz farklıdır: döviz, plasiyer kırılımı, grup şirketleri, kapama... Erp Asistanı'na ücretsiz üye olun; "60 günden uzun süredir vadesi geçmiş alacakları plasiyer bazında listele" gibi sorunuzu Türkçe yazın, Mikro şemanıza uygun çalışan SQL'i saniyeler içinde alın.

Ücretsiz üye olun, sorgunuzu doğal dille üretin →

Bu yazıyı paylaş
Konuşarak raporlayın

Mikro'da SQL ve raporu konuşarak alın

Türkçe sorunuzu yazın, şemanıza uygun çalışan SQL'i ya da hazır uygulamanızı saniyeler içinde alın. Kredi kartı gerekmez.