---
title: "Mikro ERP Tahsilat Raporu SQL: Cari Bazlı Günlük Tahsilat Detayı"
description: "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."
date: 2026-05-25
category: mikro-erp
tags: ["mikro-erp", "sql-server", "cari-hesap", "tahsilat-raporu", "046110", "cek-senet", "cha_vade", "sorgu-yonetimi", "astaflow"]
url: https://mikroerp.dev/blog/mikro-erp-cari-tahsilat-detay-raporu-sql/
---

## 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_tip` | `cha_tip` | `cha_cinsi` |
|---|---|---|---|
| Nakit | 1 | 1 | 0 |
| Kredi kartı | 1 | 1 | 19 |
| Gelen havale | 34 | 1 | 0 |
| Çek | 1, 4 | 1 | 1 |
| Senet | 1, 3 | 1 | 2 |

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:

```sql
-- İ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ı

```sql
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ür | Normal Tahsilat | İade Evrak Tipleri |
|---|---|---|
| **Çek** | `cha_evrak_tip IN (1, 4)` | `12, 13, 20, 21, 40, 41, 43, 46, 47, 74, 80, 81, 86, 87` |
| **Senet** | `cha_evrak_tip IN (1, 3)` | `16, 17, 24, 25, 39, 42, 44, 45, 48, 75, 78, 79, 84, 85` |

### Nihai Çek/Senet Formülü

```sql
-- Ç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:

| Alan | Değer | Anlam |
|---|---|---|
| `cha_cinsi` | 0 | Nakit / Havale |
| `cha_cinsi` | 1 | Çek |
| `cha_cinsi` | 2 | Senet |
| `cha_cinsi` | 19 | Kredi kartı |
| `cha_tip` | 0 | Borç |
| `cha_tip` | 1 | Alacak (Tahsilat) |
| `cha_evrak_tip` | 1 | Tahsilat makbuzu |
| `cha_evrak_tip` | 3 | Senet bordrosu |
| `cha_evrak_tip` | 4 | Çek bordrosu |
| `cha_evrak_tip` | 34 | Gelen havale |
| `cha_normal_Iade` | 0 | Normal |
| `cha_normal_Iade` | 1 | İade |

## Nihai SQL Sorgusu — SSMS Test Versiyonu

```sql
-- =============================================
-- ⚙️ 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:

```sql
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 Raporu | SQL Çö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üre | Doğ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)

*   **AstaFlow Case Study:** [Finans ve Tahsilat Hedeflemesi Modülleri](/case-study/)
*   **Mikro ERP DB API:** [CARI_HESAP_HAREKETLERI](https://apidocs.mikro.com.tr/tablo-alan-adlari/cari_hesap_hareketleri) | [CARI_HESAPLAR](https://apidocs.mikro.com.tr/tablo-alan-adlari/cari_hesaplar)
*   **İlgili Yazı:** [Cari Ekstre Raporu SQL Sorgusu](/blog/mikro-erp-cari-ekstre-raporu-sql/) — Tüm cari hareketlerin detaylı dökümü
*   **İlgili Yazı:** [Çek/Senet Vade Takip Raporu](/blog/mikro-erp-cek-senet-vade-takip-sql/) — Çek ve senet pozisyonlarının vade bazlı analizi
*   **İlgili Yazı:** [Kapanmamış Cari Hareket Raporu](/blog/mikro-erp-kapanmamis-cari-hareket-sql/) — Açık kalan tahsilatların takibi
*   **İlgili Yazı:** [Kasa ve Nakit Akış Raporu](/blog/mikro-erp-kasa-nakit-akis-raporu-sql/) — Kasa bazlı nakit giriş/çıkış analizi
*   **İlgili Araç:** [Evrak Tipi Decoder — cha_evrak_tip değerlerini anında çevirin](/araclar/evrak-tip-decoder/)