Mikro ERP Cari Yaşlandırma SQL Sorgusu: Bakiye Dağıtımlı Tam Rehber
Mikro ERP'de cari yaşlandırma raporunu SQL ile nasıl alırsınız? fn_Aysm fonksiyonları, bakiye dağıtım mantığı (FIFO aging), vade hesabı ve teminat kontrolü dahil — en kapsamlı rehber.
Neden Özel SQL Sorgusu Gerekiyor?
Mikro ERP’nin kendi içinde 046921 numaralı “Cari Hesap Bakiye Yaşlandırma Raporu” var. Tek bir müşteri veya küçük bir liste için yeterli. Ama şu durumlarda yetersiz kalır:
- Tüm carilerin yaşlandırmasını tek seferde çekmek istiyorsanız
- Sonuçları web dashboard’a, Excel’e veya başka bir sisteme aktaracaksanız
- Birden fazla şube veritabanını tek bir raporda birleştirmek istiyorsanız
- Otomatik günlük/haftalık rapor oluşturmak istiyorsanız
Bu yazıda, Mikro’nun kendi fn_Aysm fonksiyonlarını kullanan, bakiye dağıtımlı (FIFO aging) profesyonel bir yaşlandırma sorgusu paylaşıyoruz.
İnternetteki Basit Yaklaşımın Sorunu
İnternette bulacağınız çoğu sorgu şuna benzer:
-- ❌ Basit ama YANLIŞ yaklaşım
SELECT
cari_kodu,
SUM(CASE WHEN DATEDIFF(day, vade_tarihi, GETDATE()) BETWEEN 0 AND 30
THEN borc - alacak ELSE 0 END) AS [0-30 Gün],
SUM(CASE WHEN DATEDIFF(day, vade_tarihi, GETDATE()) BETWEEN 31 AND 60
THEN borc - alacak ELSE 0 END) AS [31-60 Gün]
FROM CARI_HESAP_HAREKETLERI
GROUP BY cari_kodu
Bu yaklaşımın 3 kritik sorunu var:
- Kısmi ödemeleri hesaba katmaz — Müşteri 100.000 TL’lik faturanın 60.000 TL’sini ödediyse, kalan 40.000 TL hangi döneme ait?
- Mikro’nun bakiye hesaplama mantığını kullanmaz — Döviz kuru, KDV, tevkifat, masraf gibi kalemleri atlar
- Bakiye dağıtımı yapmaz — Toplam borcu en eski faturalardan başlayarak dağıtmaz
Doğru Yaklaşım: Bakiye Dağıtımlı Yaşlandırma (FIFO)
Profesyonel yaşlandırma şöyle çalışır:
1. Carinin toplam bakiyesini hesapla (fn_Aysm ile)
2. Tüm hareketleri en yeniden en eskiye sırala
3. Bakiyeyi en yeni faturalardan başlayarak dağıt
4. Her faturanın "yaşı" evrak tarihine göre belirlenir
Örnek: Bir carinin 150.000 TL borcu var ve 3 faturası var:
Fatura 1 (Mart): 80.000 TL → Bakiyeden dağıt → 80.000 TL
Fatura 2 (Şubat): 60.000 TL → Bakiyeden dağıt → 60.000 TL
Fatura 3 (Ocak): 50.000 TL → Bakiyeden kalan → 10.000 TL
─────────
Toplam: 150.000 TL
Bu mantık, müşterinin en son ödediği tutarı en eski faturadan düşer.
Tam SQL Sorgusu (7 Adımlı)
Aşağıda Mikro ERP veritabanlarında çalışan, production-ready bir yaşlandırma sorgusu bulunuyor. Kendi yapınıza göre 3 yeri değiştirmeniz yeterli.
Değiştirmeniz Gereken Yerler
@BakiyeTarih → Raporun çekileceği tarih
'M.35%' → Cari kodlarınızın prefix'i (örn: '120%', 'MRK%', '')
Ay aralıkları → Son bölümdeki tarih aralıklarını güncel aya göre ayarlayın
Adım 1: Aktif Carileri Belirleme
Bakiye hesaplama fonksiyonu yavaş çalışır. Önce sadece hareket görmüş carileri süzüyoruz — böylece hiç hareketi olmayan binlerce cari için boşuna fonksiyon çalışmaz:
SET NOCOUNT ON;
DECLARE @BakiyeTarih datetime = GETDATE(); -- Rapor tarihi
DECLARE @GunTarih date = CAST(@BakiyeTarih AS date);
-- Temp tabloları temizle
IF OBJECT_ID('tempdb..#AktifCariler') IS NOT NULL DROP TABLE #AktifCariler;
IF OBJECT_ID('tempdb..#HamBakiye') IS NOT NULL DROP TABLE #HamBakiye;
IF OBJECT_ID('tempdb..#Bakiye') IS NOT NULL DROP TABLE #Bakiye;
IF OBJECT_ID('tempdb..#Kaynak') IS NOT NULL DROP TABLE #Kaynak;
IF OBJECT_ID('tempdb..#Dagitim') IS NOT NULL DROP TABLE #Dagitim;
-- Sadece hareket görmüş carileri çek
SELECT DISTINCT cha_kod AS cari_kod
INTO #AktifCariler
FROM dbo.CARI_HESAP_HAREKETLERI WITH (NOLOCK)
WHERE cha_tarihi <= @BakiyeTarih;
-- İsteğe bağlı: Belirli bir prefix ile filtrelemek için ekleyin:
-- AND cha_kod LIKE '120%'
💡 Performans ipucu: Eğer tüm carileri değil, belirli bir grubu çekmek istiyorsanız
WHERE cha_kod LIKE '120%'gibi bir filtre ekleyin. Bu, sorgu süresini dramatik şekilde kısaltır.
Adım 2: Bakiye Hesaplama (fn_Aysm Fonksiyonu)
Mikro’nun kendi bakiye hesaplama fonksiyonunu kullanıyoruz. Bu fonksiyon KDV, döviz kuru, masraf, tevkifat gibi tüm kalemleri hesaba katar:
SELECT
a.cari_kod,
CONVERT(decimal(18,2),
dbo.fn_Aysm_v2_CariHesapAnaDovizBakiye(
'', 0, a.cari_kod, '', '',
NULL, NULL, @BakiyeTarih, 0, 0, 0, 0, 0
)
) AS HamBakiye
INTO #HamBakiye
FROM #AktifCariler a;
⚠️ Önemli:
fn_Aysm_v2_CariHesapAnaDovizBakiyefonksiyonu Mikro güncellendikçe parametre değişikliğine uğrayabilir. Fonksiyonun veritabanınızda mevcut olduğundan emin olun. Eksikse fn_ fonksiyonları kopyalama yazımıza bakın.
Adım 3: Bakiyeleri Ayrıştırma
Sıfır bakiyeli carileri eleyin ve borç/alacak tipini belirleyin:
SELECT
cari_kod,
HamBakiye AS OrjinalBakiye, -- Ekranda eksi/artı göstermek için
ABS(HamBakiye) AS NetBakiye, -- Dağıtım matematiği için (mutlak değer)
CASE
WHEN HamBakiye > 0 THEN 0 -- Borçlu
WHEN HamBakiye < 0 THEN 1 -- Alacaklı
ELSE -1
END AS Tip
INTO #Bakiye
FROM #HamBakiye
WHERE HamBakiye <> 0;
Adım 4: Hareketleri Çekme
Bakiye dağıtımı için her carinin hareketlerini, tutar hesaplamasıyla birlikte çekiyoruz. Mikro’nun meblag fonksiyonu tüm vergi ve masraf kalemlerini hesaba katar:
SELECT
b.cari_kod AS AnaCariKod,
b.NetBakiye,
ch.cha_Guid,
ch.cha_satici_kodu,
CAST(ch.cha_tarihi AS date) AS EvrakTarihi,
-- Vade tarihi hesabı: Mikro'da vade farklı formatlarda tutulur
CASE
WHEN ch.cha_vade BETWEEN 19000101 AND 20991231 THEN
TRY_CONVERT(date, CONVERT(char(8), ch.cha_vade), 112)
WHEN ch.cha_vade BETWEEN -36500 AND -1 THEN
DATEADD(DAY, ABS(ch.cha_vade), CAST(ch.cha_tarihi AS date))
ELSE NULL
END AS VadeTarihi,
-- Tutar hesabı (fn_Aysm meblag fonksiyonu)
CONVERT(decimal(18,2),
dbo.fn_Aysm_v2_CariHesapMeblag(
ch.cha_meblag, ch.cha_aratoplam,
ch.cha_vergi1 + ch.cha_vergi2 + ch.cha_vergi3 + ch.cha_vergi4 +
ch.cha_vergi5 + ch.cha_vergi6 + ch.cha_vergi7 + ch.cha_vergi8 +
ch.cha_vergi9 + ch.cha_vergi10 +
ch.cha_ilave_edilecek_kdv1 + ch.cha_ilave_edilecek_kdv2 +
ch.cha_ilave_edilecek_kdv3 + ch.cha_ilave_edilecek_kdv4 +
ch.cha_ilave_edilecek_kdv5 + ch.cha_ilave_edilecek_kdv6 +
ch.cha_ilave_edilecek_kdv7 + ch.cha_ilave_edilecek_kdv8 +
ch.cha_ilave_edilecek_kdv9 + ch.cha_ilave_edilecek_kdv10,
ch.cha_d_kur, ch.cha_altd_kur, ch.cha_karsid_kur,
ch.cha_cinsi, ch.cha_evrak_tip, 0,
ch.cha_cari_cins, ch.cha_meblag_ana_doviz_icin_gecersiz_fl,
ch.cha_meblag_alt_doviz_icin_gecersiz_fl,
ch.cha_meblag_orj_doviz_icin_gecersiz_fl,
ch.cha_ft_masraf1, ch.cha_ft_masraf2, ch.cha_ft_masraf3,
ch.cha_ft_masraf4, ch.cha_otvtutari, ch.cha_oivtutari,
ch.cha_yuvarlama, ch.cha_tevkifat_toplam,
ch.cha_stopaj, ch.cha_savsandesfonu, ch.cha_vergifon_toplam,
ch.cha_ticaret_turu, ch.cha_kasa_hizmet, ch.cha_kasa_hizkod
)
) AS Meblag,
ch.cha_create_date
INTO #Kaynak
FROM dbo.CARI_HESAP_HAREKETLERI ch WITH (NOLOCK)
INNER JOIN #Bakiye b
ON (ch.cha_kod = b.cari_kod OR ch.cha_ciro_cari_kodu = b.cari_kod)
WHERE ch.cha_tarihi <= @BakiyeTarih
AND dbo.fn_Aysm_v2_CariharBorcAlacak(
0, ch.cha_tip, ch.cha_tpoz, ch.cha_cari_cins, ch.cha_cinsi, 0, 0, 0, 0
) = b.Tip
AND ch.cha_meblag * ch.cha_d_kur > 1
AND ch.cha_evrak_tip <> 59;
Bu adım neden önemli?
cha_ciro_cari_kodukontrolü: Cirolu çek/senet gibi işlemleri de yakalarfn_Aysm_v2_CariharBorcAlacak: Borç mu alacak mı olduğunu Mikro mantığıyla belirlercha_evrak_tip <> 59: Açılış fişlerini hariç tutar- Vade hesabı: Mikro’da vade bazen sayısal (gün sayısı) olarak tutulur, bu CASE yapısı her iki formatı da yakalar
Adım 5: Bakiye Dağıtımı (FIFO)
İşte yaşlandırmanın kalbi — bakiyeyi en yeniden en eskiye doğru dağıtıyoruz:
;WITH Sira AS (
SELECT
k.*,
SUM(k.Meblag) OVER (
PARTITION BY k.AnaCariKod
ORDER BY k.EvrakTarihi DESC, k.cha_create_date DESC, k.cha_Guid DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS KümülatifTutar
FROM #Kaynak k
),
Dagitim AS (
SELECT
AnaCariKod,
cha_Guid,
cha_satici_kodu,
EvrakTarihi,
VadeTarihi,
CASE
-- Kümülatif tutar bakiyeden küçükse: tamamını al
WHEN KümülatifTutar < NetBakiye THEN Meblag
-- Bu satırda bakiyeyi geçtiyse: kalan farkı al
WHEN KümülatifTutar - Meblag < NetBakiye THEN NetBakiye - (KümülatifTutar - Meblag)
-- Bakiye zaten dolduysa: 0
ELSE 0
END AS DagitilanTutar
FROM Sira
)
SELECT *
INTO #Dagitim
FROM Dagitim
WHERE DagitilanTutar > 0;
Bu mantık ne yapıyor?
Window function ile kümülatif toplam hesaplanır. Bakiye dolana kadar en yeni faturalardan başlayarak tutar dağıtılır. Bakiye dolduğunda kalan faturalar 0 alır.
Adım 6: Teminat Bilgileri
Carinin teminat/kredi limiti bilgisini çekiyoruz:
;WITH Teminat AS (
SELECT
ct_carikodu,
SUM(ISNULL(ct_tutari, 0)) AS CariLimiti
FROM dbo.CARI_HESAP_TEMINATLARI WITH (NOLOCK)
WHERE ISNULL(ct_iptal, 0) = 0
GROUP BY ct_carikodu
)
Adım 7: Final — Ay Bazlı Yaşlandırma Raporu
Son adımda tüm verileri birleştirip aylık dağılımı gösteriyoruz. Tarih aralıklarını kendi raporunuzun dönemine göre güncelleyin:
SELECT
c.cari_kod AS [Hesap Kodu],
LTRIM(RTRIM(CONCAT(
ISNULL(c.cari_unvan1,''), ' ', ISNULL(c.cari_unvan2,'')
))) AS [Hesap Adı],
c.cari_temsilci_kodu AS [Temsilci],
ISNULL(a.adr_il,'') AS [İl],
ISNULL(a.adr_ilce,'') AS [İlçe],
ISNULL(b.OrjinalBakiye, 0) AS [Toplam Bakiye],
CASE WHEN ISNULL(c.cari_cari_kilitli_flg, 0) = 1
THEN N'Kilitli' ELSE N'Aktif'
END AS [Durum],
ABS(ISNULL(c.cari_odemeplan_no, 0)) AS [Vade (Gün)],
CONVERT(decimal(18,2), ISNULL(t.CariLimiti, 0)) AS [Teminat],
-- Vadesi geçen toplam
CONVERT(decimal(18,2), SUM(
CASE WHEN d.VadeTarihi IS NOT NULL AND d.VadeTarihi < @GunTarih
THEN d.DagitilanTutar ELSE 0 END
)) AS [Vadesi Geçen],
-- Aylık dağılım (tarih aralıklarını güncelleyin)
CONVERT(decimal(18,2), SUM(CASE
WHEN d.EvrakTarihi >= DATEADD(MONTH, -1, DATEFROMPARTS(YEAR(@GunTarih), MONTH(@GunTarih), 1))
AND d.EvrakTarihi < DATEFROMPARTS(YEAR(@GunTarih), MONTH(@GunTarih), 1)
THEN d.DagitilanTutar ELSE 0 END)) AS [1 Ay Önce],
CONVERT(decimal(18,2), SUM(CASE
WHEN d.EvrakTarihi >= DATEADD(MONTH, -2, DATEFROMPARTS(YEAR(@GunTarih), MONTH(@GunTarih), 1))
AND d.EvrakTarihi < DATEADD(MONTH, -1, DATEFROMPARTS(YEAR(@GunTarih), MONTH(@GunTarih), 1))
THEN d.DagitilanTutar ELSE 0 END)) AS [2 Ay Önce],
CONVERT(decimal(18,2), SUM(CASE
WHEN d.EvrakTarihi >= DATEADD(MONTH, -3, DATEFROMPARTS(YEAR(@GunTarih), MONTH(@GunTarih), 1))
AND d.EvrakTarihi < DATEADD(MONTH, -2, DATEFROMPARTS(YEAR(@GunTarih), MONTH(@GunTarih), 1))
THEN d.DagitilanTutar ELSE 0 END)) AS [3 Ay Önce],
CONVERT(decimal(18,2), SUM(CASE
WHEN d.EvrakTarihi >= DATEADD(MONTH, -6, DATEFROMPARTS(YEAR(@GunTarih), MONTH(@GunTarih), 1))
AND d.EvrakTarihi < DATEADD(MONTH, -3, DATEFROMPARTS(YEAR(@GunTarih), MONTH(@GunTarih), 1))
THEN d.DagitilanTutar ELSE 0 END)) AS [3-6 Ay Önce],
CONVERT(decimal(18,2), SUM(CASE
WHEN d.EvrakTarihi < DATEADD(MONTH, -6, DATEFROMPARTS(YEAR(@GunTarih), MONTH(@GunTarih), 1))
THEN d.DagitilanTutar ELSE 0 END)) AS [6+ Ay Önce]
FROM dbo.CARI_HESAPLAR c WITH (NOLOCK)
INNER JOIN #Bakiye b ON b.cari_kod = c.cari_kod
LEFT JOIN dbo.CARI_HESAP_ADRESLERI a WITH (NOLOCK)
ON a.adr_cari_kod = c.cari_kod AND a.adr_adres_no = 1
LEFT JOIN Teminat t ON t.ct_carikodu = c.cari_kod
LEFT JOIN #Dagitim d ON d.AnaCariKod = c.cari_kod
GROUP BY
c.cari_kod, c.cari_unvan1, c.cari_unvan2,
c.cari_temsilci_kodu, a.adr_il, a.adr_ilce,
c.cari_cari_kilitli_flg, c.cari_odemeplan_no,
t.CariLimiti, b.OrjinalBakiye
ORDER BY b.OrjinalBakiye DESC;
Çıktı Neye Benzer?
Hesap Kodu │ Hesap Adı │ Bakiye │ Vadesi Geçen │ 1 Ay │ 2 Ay │ 3+ Ay
───────────┼─────────────────┼────────────┼──────────────┼───────┼───────┼───────
120.001 │ ABC Tic. Ltd. │ -245.000 │ 180.000 │ 80K │ 65K │ 100K
120.045 │ XYZ İnşaat A.Ş. │ -128.500 │ 45.000 │ 50K │ 78K │ 0
120.012 │ Demir Yapı │ -87.300 │ 87.300 │ 0 │ 40K │ 47K
Kullandığımız fn_Aysm Fonksiyonları
Bu sorguda 3 Mikro fonksiyonu kullanılıyor:
| Fonksiyon | Ne Yapar |
|---|---|
fn_Aysm_v2_CariHesapAnaDovizBakiye | Carinin toplam bakiyesini ana döviz cinsinden hesaplar |
fn_Aysm_v2_CariHesapMeblag | Tek bir hareketin net tutarını hesaplar (KDV, masraf, tevkifat dahil) |
fn_Aysm_v2_CariharBorcAlacak | Hareketin borç mu alacak mı olduğunu belirler |
Bu fonksiyonlar Mikro’nun kendi iç fonksiyonlarıdır ve tüm veritabanlarında bulunmayabilir. Fonksiyon kontrolü ve kopyalama rehberimize bakın.
Performans İpuçları
| Durum | Yaklaşık Süre |
|---|---|
| 500 cari | ~30 saniye |
| 2.000 cari | ~2 dakika |
| 5.000+ cari | 5+ dakika |
Sorguyu hızlandırmak için:
- Cari prefix filtresi kullanın —
WHERE cha_kod LIKE '120%'ile sadece istediğiniz grubu çekin - Tarih filtresi daraltın — Çok eski hareketler bakiye dağıtımını yavaşlatır
- NOLOCK — Zaten sorgudaki tüm tablo erişimlerinde
WITH (NOLOCK)kullanılıyor - Zamanlama — Mesai saatleri dışında çalıştırın, SQL Server’ı meşgul eder
Dikkat Edilecekler
SET LANGUAGE Turkish Tuzağı
Bu sorgu SET LANGUAGE Turkish içermiyor — bilerek çıkarıldı. Türkçe dil ayarı tarih hesaplamalarını bozabilir. Detaylı açıklama.
fn_Aysm Fonksiyonu Bulunamadı Hatası
Invalid object name 'dbo.fn_Aysm_v2_CariHesapAnaDovizBakiye'
Bu fonksiyonlar Mikro güncellendikten sonra bazı şube veritabanlarına eklenmemiş olabilir. Çözüm: Fonksiyonun var olduğu bir veritabanından kopyalayın. Rehberimiz.
Bakiye Mikro ile Uyuşmuyor
- Rapor tarihinin Mikro’daki ile aynı olduğundan emin olun
- Döviz cinsini kontrol edin (sorgu ana döviz bakiyesini alır)
- Açılış fişleri (
cha_evrak_tip = 59) hariç tutulmuştur — gerekirse dahil edin
Bu Sorguyu Web’e Taşımak
Bu SQL sorgusunu her sabah otomatik çalıştırıp sonuçları web dashboard’a aktarabilirsiniz. Cari yaşlandırma otomasyon yazımız bu süreci adım adım anlatıyor.
Tam Sorgu — Kopyala Yapıştır
Yukarıdaki 7 adımın tamamı tek bir blok halinde. SSMS’e yapıştırın, @BakiyeTarih değerini ayarlayın, çalıştırın:
/*
Mikro ERP — Cari Yaşlandırma (Bakiye Dağıtımlı / FIFO)
─────────────────────────────────────────────────────────
Kullanım:
1. @BakiyeTarih → Rapor tarihi (varsayılan: bugün)
2. Cari filtresi → Adım 1'deki WHERE satırını açın
3. SSMS'de çalıştırın
Gerekli fonksiyonlar:
- dbo.fn_Aysm_v2_CariHesapAnaDovizBakiye
- dbo.fn_Aysm_v2_CariHesapMeblag
- dbo.fn_Aysm_v2_CariharBorcAlacak
*/
SET NOCOUNT ON;
DECLARE @BakiyeTarih datetime = GETDATE(); -- İstediğiniz tarihi yazın: '20240315'
DECLARE @GunTarih date = CAST(@BakiyeTarih AS date);
-- Temp tabloları temizle
IF OBJECT_ID('tempdb..#AktifCariler') IS NOT NULL DROP TABLE #AktifCariler;
IF OBJECT_ID('tempdb..#HamBakiye') IS NOT NULL DROP TABLE #HamBakiye;
IF OBJECT_ID('tempdb..#Bakiye') IS NOT NULL DROP TABLE #Bakiye;
IF OBJECT_ID('tempdb..#Kaynak') IS NOT NULL DROP TABLE #Kaynak;
IF OBJECT_ID('tempdb..#Dagitim') IS NOT NULL DROP TABLE #Dagitim;
----------------------------------------------------------------------
-- 1. Aktif carileri belirle (performans için ön filtre)
----------------------------------------------------------------------
SELECT DISTINCT cha_kod AS cari_kod
INTO #AktifCariler
FROM dbo.CARI_HESAP_HAREKETLERI WITH (NOLOCK)
WHERE cha_tarihi <= @BakiyeTarih;
-- 👉 Belirli bir grup için: AND cha_kod LIKE '120%'
----------------------------------------------------------------------
-- 2. Bakiye hesapla (fn_Aysm fonksiyonu)
----------------------------------------------------------------------
SELECT
a.cari_kod,
CONVERT(decimal(18,2),
dbo.fn_Aysm_v2_CariHesapAnaDovizBakiye(
'', 0, a.cari_kod, '', '',
NULL, NULL, @BakiyeTarih, 0, 0, 0, 0, 0
)
) AS HamBakiye
INTO #HamBakiye
FROM #AktifCariler a;
----------------------------------------------------------------------
-- 3. Sıfır bakiyeleri ele, borç/alacak tipini belirle
----------------------------------------------------------------------
SELECT
cari_kod,
HamBakiye AS OrjinalBakiye,
ABS(HamBakiye) AS NetBakiye,
CASE WHEN HamBakiye > 0 THEN 0
WHEN HamBakiye < 0 THEN 1
ELSE -1 END AS Tip
INTO #Bakiye
FROM #HamBakiye
WHERE HamBakiye <> 0;
----------------------------------------------------------------------
-- 4. Hareketleri çek (tutar + vade hesabıyla)
----------------------------------------------------------------------
SELECT
b.cari_kod AS AnaCariKod,
b.NetBakiye,
ch.cha_Guid,
ch.cha_satici_kodu,
CAST(ch.cha_tarihi AS date) AS EvrakTarihi,
CASE
WHEN ch.cha_vade BETWEEN 19000101 AND 20991231 THEN
TRY_CONVERT(date, CONVERT(char(8), ch.cha_vade), 112)
WHEN ch.cha_vade BETWEEN -36500 AND -1 THEN
DATEADD(DAY, ABS(ch.cha_vade), CAST(ch.cha_tarihi AS date))
ELSE NULL
END AS VadeTarihi,
CONVERT(decimal(18,2),
dbo.fn_Aysm_v2_CariHesapMeblag(
ch.cha_meblag, ch.cha_aratoplam,
ch.cha_vergi1 + ch.cha_vergi2 + ch.cha_vergi3 + ch.cha_vergi4 +
ch.cha_vergi5 + ch.cha_vergi6 + ch.cha_vergi7 + ch.cha_vergi8 +
ch.cha_vergi9 + ch.cha_vergi10 +
ch.cha_ilave_edilecek_kdv1 + ch.cha_ilave_edilecek_kdv2 +
ch.cha_ilave_edilecek_kdv3 + ch.cha_ilave_edilecek_kdv4 +
ch.cha_ilave_edilecek_kdv5 + ch.cha_ilave_edilecek_kdv6 +
ch.cha_ilave_edilecek_kdv7 + ch.cha_ilave_edilecek_kdv8 +
ch.cha_ilave_edilecek_kdv9 + ch.cha_ilave_edilecek_kdv10,
ch.cha_d_kur, ch.cha_altd_kur, ch.cha_karsid_kur,
ch.cha_cinsi, ch.cha_evrak_tip, 0,
ch.cha_cari_cins, ch.cha_meblag_ana_doviz_icin_gecersiz_fl,
ch.cha_meblag_alt_doviz_icin_gecersiz_fl,
ch.cha_meblag_orj_doviz_icin_gecersiz_fl,
ch.cha_ft_masraf1, ch.cha_ft_masraf2, ch.cha_ft_masraf3,
ch.cha_ft_masraf4, ch.cha_otvtutari, ch.cha_oivtutari,
ch.cha_yuvarlama, ch.cha_tevkifat_toplam,
ch.cha_stopaj, ch.cha_savsandesfonu, ch.cha_vergifon_toplam,
ch.cha_ticaret_turu, ch.cha_kasa_hizmet, ch.cha_kasa_hizkod
)
) AS Meblag,
ch.cha_create_date
INTO #Kaynak
FROM dbo.CARI_HESAP_HAREKETLERI ch WITH (NOLOCK)
INNER JOIN #Bakiye b
ON (ch.cha_kod = b.cari_kod OR ch.cha_ciro_cari_kodu = b.cari_kod)
WHERE ch.cha_tarihi <= @BakiyeTarih
AND dbo.fn_Aysm_v2_CariharBorcAlacak(
0, ch.cha_tip, ch.cha_tpoz, ch.cha_cari_cins, ch.cha_cinsi, 0, 0, 0, 0
) = b.Tip
AND ch.cha_meblag * ch.cha_d_kur > 1
AND ch.cha_evrak_tip <> 59;
----------------------------------------------------------------------
-- 5. Bakiye dağıtımı (FIFO — en yeniden eskiye)
----------------------------------------------------------------------
;WITH Sira AS (
SELECT k.*,
SUM(k.Meblag) OVER (
PARTITION BY k.AnaCariKod
ORDER BY k.EvrakTarihi DESC, k.cha_create_date DESC, k.cha_Guid DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS CumTutar
FROM #Kaynak k
),
Dagitim AS (
SELECT AnaCariKod, cha_Guid, cha_satici_kodu, EvrakTarihi, VadeTarihi,
CASE
WHEN CumTutar < NetBakiye THEN Meblag
WHEN CumTutar - Meblag < NetBakiye THEN NetBakiye - (CumTutar - Meblag)
ELSE 0
END AS DagitilanTutar
FROM Sira
)
SELECT * INTO #Dagitim FROM Dagitim WHERE DagitilanTutar > 0;
----------------------------------------------------------------------
-- 6 + 7. Teminatlar + Final rapor
----------------------------------------------------------------------
;WITH Teminat AS (
SELECT ct_carikodu,
SUM(ISNULL(ct_tutari, 0)) AS CariLimiti
FROM dbo.CARI_HESAP_TEMINATLARI WITH (NOLOCK)
WHERE ISNULL(ct_iptal, 0) = 0
GROUP BY ct_carikodu
)
SELECT
c.cari_kod AS [Hesap Kodu],
LTRIM(RTRIM(CONCAT(ISNULL(c.cari_unvan1,''),' ',ISNULL(c.cari_unvan2,'')))) AS [Hesap Adı],
c.cari_temsilci_kodu AS [Temsilci],
ISNULL(a.adr_il,'') AS [İl],
ISNULL(a.adr_ilce,'') AS [İlçe],
ISNULL(b.OrjinalBakiye, 0) AS [Toplam Bakiye],
CASE WHEN ISNULL(c.cari_cari_kilitli_flg,0)=1 THEN N'Kilitli' ELSE N'Aktif' END AS [Durum],
ABS(ISNULL(c.cari_odemeplan_no,0)) AS [Vade (Gün)],
CONVERT(decimal(18,2), ISNULL(t.CariLimiti,0)) AS [Teminat],
CONVERT(decimal(18,2), SUM(CASE WHEN d.VadeTarihi IS NOT NULL AND d.VadeTarihi < @GunTarih
THEN d.DagitilanTutar ELSE 0 END)) AS [Vadesi Geçen],
CONVERT(decimal(18,2), SUM(CASE
WHEN d.EvrakTarihi >= DATEADD(MONTH,-1,DATEFROMPARTS(YEAR(@GunTarih),MONTH(@GunTarih),1))
AND d.EvrakTarihi < DATEFROMPARTS(YEAR(@GunTarih),MONTH(@GunTarih),1)
THEN d.DagitilanTutar ELSE 0 END)) AS [1 Ay Önce],
CONVERT(decimal(18,2), SUM(CASE
WHEN d.EvrakTarihi >= DATEADD(MONTH,-2,DATEFROMPARTS(YEAR(@GunTarih),MONTH(@GunTarih),1))
AND d.EvrakTarihi < DATEADD(MONTH,-1,DATEFROMPARTS(YEAR(@GunTarih),MONTH(@GunTarih),1))
THEN d.DagitilanTutar ELSE 0 END)) AS [2 Ay Önce],
CONVERT(decimal(18,2), SUM(CASE
WHEN d.EvrakTarihi >= DATEADD(MONTH,-3,DATEFROMPARTS(YEAR(@GunTarih),MONTH(@GunTarih),1))
AND d.EvrakTarihi < DATEADD(MONTH,-2,DATEFROMPARTS(YEAR(@GunTarih),MONTH(@GunTarih),1))
THEN d.DagitilanTutar ELSE 0 END)) AS [3 Ay Önce],
CONVERT(decimal(18,2), SUM(CASE
WHEN d.EvrakTarihi >= DATEADD(MONTH,-6,DATEFROMPARTS(YEAR(@GunTarih),MONTH(@GunTarih),1))
AND d.EvrakTarihi < DATEADD(MONTH,-3,DATEFROMPARTS(YEAR(@GunTarih),MONTH(@GunTarih),1))
THEN d.DagitilanTutar ELSE 0 END)) AS [3-6 Ay Önce],
CONVERT(decimal(18,2), SUM(CASE
WHEN d.EvrakTarihi < DATEADD(MONTH,-6,DATEFROMPARTS(YEAR(@GunTarih),MONTH(@GunTarih),1))
THEN d.DagitilanTutar ELSE 0 END)) AS [6+ Ay Önce]
FROM dbo.CARI_HESAPLAR c WITH (NOLOCK)
INNER JOIN #Bakiye b ON b.cari_kod = c.cari_kod
LEFT JOIN dbo.CARI_HESAP_ADRESLERI a WITH (NOLOCK)
ON a.adr_cari_kod = c.cari_kod AND a.adr_adres_no = 1
LEFT JOIN Teminat t ON t.ct_carikodu = c.cari_kod
LEFT JOIN #Dagitim d ON d.AnaCariKod = c.cari_kod
GROUP BY c.cari_kod, c.cari_unvan1, c.cari_unvan2, c.cari_temsilci_kodu,
a.adr_il, a.adr_ilce, c.cari_cari_kilitli_flg, c.cari_odemeplan_no,
t.CariLimiti, b.OrjinalBakiye
ORDER BY b.OrjinalBakiye DESC;
İlgili Yazılar
- fn_ Fonksiyonlarını Şubelere Kopyalama
- SET LANGUAGE Turkish Tarih Tuzağı
- Cari Yaşlandırma Web Otomasyonu
- SQL Server’a Web’den Güvenli Bağlantı
Bu yazı AstaFlow Case Study serisinin bir parçasıdır — 8 şubeli bir yapıda cari yaşlandırma otomasyonu sırasında geliştirdiğimiz sorgunun genelleştirilmiş halidir.