Mikro ERP Tahsilat Raporu SQL: Cari Bazlı Günlük Tahsilat Detayı

Mikro ERP 046110 Tahsilat Özet Raporunun SQL alternatifi. Nakit, kredi kartı, havale, çek ve senet ayrımı, cha_vade tuzağı, çek/senet iade mantığı ve Mikro Menü Sorgu Yönetimi uyumlu SQL sorgusu.

Problem: Mikro 046110 Raporunun Yetersiz Kaldığı Nokta

Mikro ERP’de tahsilat takibi için 046110 — Tahsilat Özet Raporu kullanılır. Bu rapor belirli bir tarih aralığında cari bazında tahsilat toplamlarını gösterir.

Ancak pratikte bu rapor iki önemli sorun yaratıyor:

  1. Yavaş. Geniş tarih aralığı ve çok sayıda cari için ciddi süre alıyor.
  2. Gün bazlı kırılım yok. Bir ay seçtiğinizde her carinin toplam tahsilatını görüyorsunuz, ama hangi gün hangi cari ne kadar ödemiş sorusuna cevap veremiyor.

Biz ise şunu istiyoruz:

  • Tarih aralığı içindeki tahsilatları gün gün, cari bazında görmek.
  • Temsilci kodu ile kimin müşterisi olduğunu bilmek.
  • Nakit, kredi kartı, gelen havale, çek ve senet tutarlarını ayrı sütunlarda görmek.
  • Çek/senet iadelerini de dahil etmek.
  • Sonucu Excel’e aktarılabilir ve Mikro Menü Sorgu Yönetimi’nde çalışabilir formatta sunmak.

Bu yazıda, 046110 raporunun sağlayamadığı bu detayı SQL ile nasıl ürettiğimizi, süreçte düştüğümüz tuzakları ve çözümlerini paylaşıyoruz.

İlk Adım: Tahsilat Türlerinin Ayrıştırılması

CARI_HESAP_HAREKETLERI tablosunda tahsilat türleri üç alan kombinasyonuyla belirlenir:

Tahsilat Türücha_evrak_tipcha_tipcha_cinsi
Nakit110
Kredi kartı1119
Gelen havale3410
Çek1, 411
Senet1, 312

Bu üç alan (cha_evrak_tip, cha_tip, cha_cinsi) tahsilat türünü belirleyen üç bileşendir. Mikro’nun dahili raporları da bu eşleşmeleri kullanır.

Kritik Hata: Çekte cha_vade Tuzağı

Çek hareketlerinde cha_vade alanı dolu olduğu için ilk denemede çek tahsilatını vade tarihine göre rapora dahil ettik. Mantık şuydu:

-- İlk (yanlış) yaklaşım: vade tarihine göre filtreleme
cha_cinsi = 1
AND cha_vade = CAST(CONVERT(varchar(8), @Tarih, 112) AS int)

Bu yaklaşımla çekler vadelerine göre rapora düşüyordu. Ama Mikro’nun 046110 raporuyla karşılaştırdığımızda sonuçlar eşleşmedi.

Sonra tek cari üzerinden Mikro ekranıyla karşılaştırdık:

Örnek çek hareketi:
  Hareket tarihi:  10.04.2026
  Çek vadesi:      08.09.2026
  Tutar:           250.000 ₺

Mikro’nun orijinal raporunda bu çek Nisan tahsilatı olarak görünüyordu — çünkü çekin alındığı tarih 10 Nisan’dır. Vade tarihi ise Eylül.

Ders: Tahsilat raporu için çekin rapora dahil edilme tarihi cha_tarihi (işlem tarihi) olmalıdır. cha_vade ancak valör hesabı veya ortalama vade analizi için anlamlıdır.

Tüm tahsilat tipleri için ana tarih filtresi cha_tarihi üzerinden kurulmalıdır.

Rapor Yapısının Evrimi

İlk Versiyon: Aşırı Detay

İlk denemede satır bazında tüm teknik alanlar yer alıyordu:

Tarih | Tahsilat Tipi | Vade | Cari Kodu | Ünvan | Evrak Seri | 
Evrak Sıra | Belge No | Açıklama | Evrak Tip | Cinsi | Tip | Tutar

Teknik analiz için faydalı ama günlük kullanım için fazla gürültülü ve Excel’e aktarıldığında okunaksız.

Nihai Versiyon: Temiz ve Pratik

Tarih | Temsilci | Cari Kodu | Cari Adı | Nakit | K.Kartı | Havale | Çek | Senet | Toplam

Her cari/tarih/temsilci kırılımında tek satır — tahsilat türleri yan yana sütunlarda. Excel’e aktarıldığında pivot tablo gibi çalışıyor.

İkinci Hata: Çek/Senet İadelerinin Eksik Kalması

Temiz raporu geniş tarih aralığıyla test ettiğimizde yeni bir sorun çıktı:

Örnek cari doğrulaması:

Mikro orijinal rapor:          Bizim SQL:
  Nakit:        40.000 ₺         40.000 ₺  ✓
  Kredi kartı:  10.000 ₺         10.000 ₺  ✓
  Senet:       -40.000 ₺              0 ₺  ✗ ← Eksik!
  Toplam:       10.000 ₺         50.000 ₺  ✗

40.000 ₺‘lik senet iadesi raporumuza yansımıyordu. Sadece cha_tip = 1 (tahsilat) hareketlerini aldığımız için iade hareketleri tamamen dışarıda kalıyordu.

Çek/Senet İade Mantığı

İade hareketlerini yakalamak için iki mekanizma kullanılıyor:

1. cha_normal_Iade Alanı

cha_normal_Iade = 0  →  Normal hareket
cha_normal_Iade = 1  →  İade hareketi

2. İade Evrak Tipleri

Çek ve senet iadeleri belirli evrak tipi kodlarıyla da kaydedilir:

TürNormal Tahsilatİade Evrak Tipleri
Çekcha_evrak_tip IN (1, 4)12, 13, 20, 21, 40, 41, 43, 46, 47, 74, 80, 81, 86, 87
Senetcha_evrak_tip IN (1, 3)16, 17, 24, 25, 39, 42, 44, 45, 48, 75, 78, 79, 84, 85

Nihai Çek/Senet Formülü

-- Çek: Normal + İade
CASE
    -- Normal çek tahsilatı → pozitif
    WHEN cha_cinsi = 1
         AND cha_tip = 1
         AND cha_evrak_tip IN (1, 4)
         AND ISNULL(cha_normal_Iade, 0) = 0
    THEN cha_meblag

    -- Çek iadesi → negatif
    WHEN cha_cinsi = 1
         AND (
               ISNULL(cha_normal_Iade, 0) = 1
               OR cha_tip = 0
               OR cha_evrak_tip IN (
                   12, 13, 20, 21, 40, 41, 43,
                   46, 47, 74, 80, 81, 86, 87
               )
         )
    THEN cha_meblag * -1

    ELSE 0
END AS [Çek]

Senet için de aynı yaklaşım, farklı evrak tip kodlarıyla uygulandı.

Tahsilat Türü Referans Tablosu

Sorguyu kendinize uyarlarken bu referans tablosunu kullanabilirsiniz:

AlanDeğerAnlam
cha_cinsi0Nakit / Havale
cha_cinsi1Çek
cha_cinsi2Senet
cha_cinsi19Kredi kartı
cha_tip0Borç
cha_tip1Alacak (Tahsilat)
cha_evrak_tip1Tahsilat makbuzu
cha_evrak_tip3Senet bordrosu
cha_evrak_tip4Çek bordrosu
cha_evrak_tip34Gelen havale
cha_normal_Iade0Normal
cha_normal_Iade1İade

Nihai SQL Sorgusu — SSMS Test Versiyonu

-- =============================================
-- ⚙️ SSMS Test: Tarihleri kendi aralığınıza göre değiştirin
-- Mikro Menü Sorgu Yönetimi'ne alırken DECLARE satırlarını kaldırın
-- =============================================
DECLARE @P1 DATE = '2026-04-01';
DECLARE @P2 DATE = '2026-04-30';

SELECT
    X.[Tarih],
    X.[Temsilci Kodu],
    X.[Cari Kodu],
    X.[Cari Ünvan],

    ROUND(SUM(X.[Nakit]), 2) AS [Nakit],
    ROUND(SUM(X.[Kredi Kartı]), 2) AS [Kredi Kartı],
    ROUND(SUM(X.[Gelen Havale]), 2) AS [Gelen Havale],
    ROUND(SUM(X.[Çek]), 2) AS [Çek],
    ROUND(SUM(X.[Senet]), 2) AS [Senet],

    ROUND(
        SUM(X.[Nakit])
        + SUM(X.[Kredi Kartı])
        + SUM(X.[Gelen Havale])
        + SUM(X.[Çek])
        + SUM(X.[Senet])
    , 2) AS [Toplam]

FROM
(
    SELECT
        CHA.cha_tarihi AS [Tarih],
        CHA.cha_satici_kodu AS [Temsilci Kodu],
        CHA.cha_kod AS [Cari Kodu],
        LTRIM(RTRIM(
            ISNULL(CH.cari_unvan1, '') + ' ' + ISNULL(CH.cari_unvan2, '')
        )) AS [Cari Ünvan],

        -- Nakit tahsilat
        CASE
            WHEN CHA.cha_evrak_tip = 1
                 AND CHA.cha_tip = 1
                 AND CHA.cha_cinsi = 0
                 AND ISNULL(CHA.cha_normal_Iade, 0) = 0
            THEN CHA.cha_meblag
            ELSE 0
        END AS [Nakit],

        -- Kredi kartı tahsilatı
        CASE
            WHEN CHA.cha_evrak_tip = 1
                 AND CHA.cha_tip = 1
                 AND CHA.cha_cinsi = 19
                 AND ISNULL(CHA.cha_normal_Iade, 0) = 0
            THEN CHA.cha_meblag
            ELSE 0
        END AS [Kredi Kartı],

        -- Gelen havale
        CASE
            WHEN CHA.cha_evrak_tip = 34
                 AND CHA.cha_tip = 1
                 AND CHA.cha_cinsi = 0
                 AND ISNULL(CHA.cha_normal_Iade, 0) = 0
            THEN CHA.cha_meblag
            ELSE 0
        END AS [Gelen Havale],

        -- Çek: Normal tahsilat + iade
        CASE
            WHEN CHA.cha_cinsi = 1
                 AND CHA.cha_tip = 1
                 AND CHA.cha_evrak_tip IN (1, 4)
                 AND ISNULL(CHA.cha_normal_Iade, 0) = 0
            THEN CHA.cha_meblag

            WHEN CHA.cha_cinsi = 1
                 AND (
                       ISNULL(CHA.cha_normal_Iade, 0) = 1
                       OR CHA.cha_tip = 0
                       OR CHA.cha_evrak_tip IN (
                           12, 13, 20, 21, 40, 41, 43,
                           46, 47, 74, 80, 81, 86, 87
                       )
                 )
            THEN CHA.cha_meblag * -1

            ELSE 0
        END AS [Çek],

        -- Senet: Normal tahsilat + iade
        CASE
            WHEN CHA.cha_cinsi = 2
                 AND CHA.cha_tip = 1
                 AND CHA.cha_evrak_tip IN (1, 3)
                 AND ISNULL(CHA.cha_normal_Iade, 0) = 0
            THEN CHA.cha_meblag

            WHEN CHA.cha_cinsi = 2
                 AND (
                       ISNULL(CHA.cha_normal_Iade, 0) = 1
                       OR CHA.cha_tip = 0
                       OR CHA.cha_evrak_tip IN (
                           16, 17, 24, 25, 39, 42, 44,
                           45, 48, 75, 78, 79, 84, 85
                       )
                 )
            THEN CHA.cha_meblag * -1

            ELSE 0
        END AS [Senet]

    FROM dbo.CARI_HESAP_HAREKETLERI CHA WITH (NOLOCK)

    LEFT JOIN dbo.CARI_HESAPLAR CH WITH (NOLOCK)
        ON CH.cari_kod = CHA.cha_kod

    WHERE
        CHA.cha_tarihi >= @P1
        AND CHA.cha_tarihi <= @P2
        AND CHA.cha_kod LIKE 'M.%'          -- ⚙️ Müşteri carileri
        AND CHA.cha_cinsi IN (0, 1, 2, 19)
        AND (
                -- Nakit
                (
                    CHA.cha_evrak_tip = 1
                    AND CHA.cha_cinsi = 0
                    AND CHA.cha_tip = 1
                    AND ISNULL(CHA.cha_normal_Iade, 0) = 0
                )
                OR
                -- Kredi kartı
                (
                    CHA.cha_evrak_tip = 1
                    AND CHA.cha_cinsi = 19
                    AND CHA.cha_tip = 1
                    AND ISNULL(CHA.cha_normal_Iade, 0) = 0
                )
                OR
                -- Gelen havale
                (
                    CHA.cha_evrak_tip = 34
                    AND CHA.cha_cinsi = 0
                    AND CHA.cha_tip = 1
                    AND ISNULL(CHA.cha_normal_Iade, 0) = 0
                )
                OR
                -- Çek: Normal + iade
                (
                    CHA.cha_cinsi = 1
                    AND (
                            (
                                CHA.cha_tip = 1
                                AND CHA.cha_evrak_tip IN (1, 4)
                                AND ISNULL(CHA.cha_normal_Iade, 0) = 0
                            )
                            OR
                            (
                                ISNULL(CHA.cha_normal_Iade, 0) = 1
                                OR CHA.cha_tip = 0
                                OR CHA.cha_evrak_tip IN (
                                    12, 13, 20, 21, 40, 41, 43,
                                    46, 47, 74, 80, 81, 86, 87
                                )
                            )
                    )
                )
                OR
                -- Senet: Normal + iade
                (
                    CHA.cha_cinsi = 2
                    AND (
                            (
                                CHA.cha_tip = 1
                                AND CHA.cha_evrak_tip IN (1, 3)
                                AND ISNULL(CHA.cha_normal_Iade, 0) = 0
                            )
                            OR
                            (
                                ISNULL(CHA.cha_normal_Iade, 0) = 1
                                OR CHA.cha_tip = 0
                                OR CHA.cha_evrak_tip IN (
                                    16, 17, 24, 25, 39, 42, 44,
                                    45, 48, 75, 78, 79, 84, 85
                                )
                            )
                    )
                )
        )

) X

GROUP BY
    X.[Tarih],
    X.[Temsilci Kodu],
    X.[Cari Kodu],
    X.[Cari Ünvan]

HAVING
    ROUND(
        SUM(X.[Nakit])
        + SUM(X.[Kredi Kartı])
        + SUM(X.[Gelen Havale])
        + SUM(X.[Çek])
        + SUM(X.[Senet])
    , 2) <> 0

ORDER BY
    X.[Tarih],
    X.[Temsilci Kodu],
    X.[Cari Kodu];

Mikro Menü Sorgu Yönetimi: @P1 / @P2 Parametreleri

Sorguyu Mikro’nun kendi Menü Sorgu Yönetimi ekranından kullanacaksanız önemli bir fark var:

SSMS’de tarih parametrelerini kendiniz tanımlamanız gerekir:

DECLARE @P1 DATE = '2026-04-01';
DECLARE @P2 DATE = '2026-04-30';

Mikro Menü Sorgu Yönetimi’nde bu DECLARE satırları kaldırılmalıdır. @P1 ve @P2 parametreleri Mikro tarafından ekran üzerinden otomatik olarak gönderilir.

Doğrulama Yöntemi: Tek Cari Üzerinden Karşılaştırma

Raporu canlıya almadan önce mutlaka şu kontrol yapılmalıdır:

  1. Mikro ekranından bir cari seçin ve hareket föyünü açın.
  2. Aynı tarih aralığında SQL sorgunuzu çalıştırın.
  3. Her tahsilat türünü tek tek karşılaştırın.

Özellikle şu durumlara dikkat edin:

  • Senet iadesi olan cariler — İade negatif olarak mı gösteriliyor?
  • Hem nakit hem çek tahsilatı olan cariler — Türler doğru sütuna mı düşüyor?
  • Ay toplamları — Orijinal günlük toplam raporuyla ay bazında toplam eşleşiyor mu?

Dikkat Edilmesi Gereken Noktalar

cha_meblag ve Ana Döviz Farkı

Bu sorguda tutarlar cha_meblag üzerinden alınmıştır. Mikro orijinal raporu bazı durumlarda ana döviz borç/alacak alanlarını kullanabilir. Testlerimizde cha_meblag değerlerinin orijinal raporla uyumlu olduğunu gördük, ancak dövizli cari hareketlerinde küçük farklar oluşabilir.

Evrak Tipleri Firmaya Özel Olabilir

Çek ve senet iade evrak tip kodları (12, 13, 20, 21...) Mikro’nun genel yapısına göre eklenmiştir. Ancak her firmada kullanılan evrak tipi kombinasyonları farklı olabilir.

Canlıya almadan önce sorunlu bir cari bazında cha_evrak_tip, cha_cinsi, cha_tip, cha_normal_Iade kombinasyonlarını kontrol edin.

NOLOCK Kullanımı

Sorguda WITH (NOLOCK) kullanıldı. Bu, rapor ekranlarında kilitlenme riskini azaltır ve okuma performansını artırır. Ancak çok yoğun işlem anında henüz kesinleşmemiş veriyi okuyabilir. Finansal kapanış veya kesin mutabakat raporu için NOLOCK kaldırılması değerlendirilebilir.

Müşteri Cari Filtresi

Sorguda cha_kod LIKE 'M.%' filtresi müşteri carilerini getirir. Bu yapı kuruma özeldir — kendi cari kod şemanıza göre düzenleyin. LIKE 'M%' daha geniştir ve M ile başlayan her kodu getirir; LIKE 'M.%' ise noktalı yapıyı zorunlu kılar.

Ne Kazandık?

046110 RaporuSQL Çözümümüz
Tarih aralığında cari toplamıGün gün, cari bazında, temsilci bazında detay
Yavaş, geniş aralıkta uzun süreDoğrudan tablo sorgusu, hızlı sonuç
Tahsilat türü ayrımı sınırlıNakit, K.K., havale, çek, senet ayrı sütunlarda
Çek/senet iadesi net görünmüyorİadeler negatif tutar olarak açıkça gösteriliyor
Mikro arayüzüne bağımlıSSMS + Mikro Menü Sorgu Yönetimi + Excel uyumlu

Bu Bilgiyi Nereden Biliyoruz? (Kaynaklar)

📚 İlgili Yazılar