---
title: "Mikro ERP'de Çek ve Senet Gerçek Tahsilat Tarihi: İşlem Tarihi vs Vade Tarihi Farkı"
description: "Mikro ERP'de çek ile ödeme yapıldığında cha_tarihi çekin alındığı gündür, gerçek tahsilat ise cha_vade tarihinde gerçekleşir. İşlem tarihi ile gerçek tahsilat tarihi ayrımı, cha_cinsi kodları ve tahsilat aracı dağılımı SQL sorgusu."
date: 2026-06-27
category: mikro-erp
tags: ["mikro-erp", "sql-server", "cari-hesap", "cek-senet", "tahsilat", "cha_cinsi", "cha_vade", "gercek-tahsilat-tarihi", "astaflow"]
url: https://mikroerp.dev/blog/mikro-erp-cek-senet-gercek-tahsilat-tarihi-sql/
---

## Sorun: "Çeki Aldım" = "Parayı Aldım" mı?

Bir müşteri 20 Aralık tarihli faturasına karşılık 15 Ocak'ta size bir **çek** veriyor. Çekin vadesi 30 Mart.

Mikro ERP'de bu hareket şöyle kayıt altına alınır:

| Alan | Değer | Anlam |
|---|---|---|
| `cha_tarihi` | 15 Ocak | Çekin alındığı tarih |
| `cha_vade` | 20260330 | Çekin vadesi (30 Mart) |
| `cha_cinsi` | 1 | Müşteri Çeki |

Şimdi bu müşterinin **ödeme süresi** nedir?

- **İşlem tarihine göre:** Fatura (20 Aralık) → Çek alındı (15 Ocak) = **26 gün** 🟢
- **Gerçek tahsilata göre:** Fatura (20 Aralık) → Çek vadesi (30 Mart) = **100 gün** 🔴

Aradaki **74 günlük fark**, nakit akışı planlamasında hayati önem taşır. Çeki almanız paranın kasanıza girdiği anlamına gelmez — vade tarihine kadar beklemeniz (veya kırdırmanız) gerekir.

## cha_cinsi Tahsilat Türleri Tablosu

Mikro ERP'de her cari hareketin `cha_cinsi` alanı tahsilat aracını belirler. Her aracın "gerçek tahsilat" anı farklıdır:

| cha_cinsi | Açıklama | Gerçek Tahsilat Anı |
|---|---|---|
| 0 | Nakit / Havale | `cha_tarihi` (anında) |
| 1 | Müşteri Çeki | `cha_vade` (vade tarihinde) |
| 2 | Müşteri Senedi | `cha_vade` (vade tarihinde) |
| 3 | Firma Çeki | `cha_tarihi` (anında) |
| 4 | Firma Senedi | `cha_tarihi` (anında) |
| 5 | Dekont | `cha_tarihi` (anında) |
| 19 | Kredi Kartı | `cha_tarihi` (anında) |

**Kritik fark:** Müşteri çeki (1) ve müşteri senedi (2) vade tarihinde tahsil edilir. Diğer tüm araçlar işlem tarihinde.

## SQL: Gerçek Tahsilat Tarihi Hesaplama

Aşağıdaki sorguyu kendi veritabanınızda çalıştırarak her tahsilatın gerçek tarihini görebilirsiniz:

```sql
DECLARE @CariKod VARCHAR(50) = '120.001'; -- Kendi cari kodunuzu yazin

SELECT
    CAST(ch.cha_tarihi AS date) AS [Islem Tarihi],
    ch.cha_cinsi,
    CASE ch.cha_cinsi
        WHEN 0 THEN 'Nakit/Havale'
        WHEN 1 THEN 'Musteri Ceki'
        WHEN 2 THEN 'Musteri Senedi'
        WHEN 19 THEN 'Kredi Karti'
        ELSE 'Diger (' + CAST(ch.cha_cinsi AS VARCHAR) + ')'
    END AS [Tahsilat Turu],
    ch.cha_meblag AS [Tutar],
    ch.cha_evrakno_seri + '-' + CAST(ch.cha_evrakno_sira AS VARCHAR) AS [Evrak No],

    -- Gercek tahsilat tarihi
    CASE
        WHEN ch.cha_cinsi IN (1, 2) THEN  -- Cek veya Senet
            CASE
                -- Format 1: YYYYMMDD (orn: 20260330)
                WHEN ch.cha_vade BETWEEN 19000101 AND 20991231 THEN
                    TRY_CONVERT(date, CONVERT(char(8), ch.cha_vade), 112)
                -- Format 2: Negatif gun sayisi (orn: -90)
                WHEN ch.cha_vade BETWEEN -36500 AND -1 THEN
                    DATEADD(DAY, ABS(ch.cha_vade), CAST(ch.cha_tarihi AS date))
                -- Vade bilgisi yok
                ELSE CAST(ch.cha_tarihi AS date)
            END
        ELSE CAST(ch.cha_tarihi AS date)  -- Nakit, KK, Havale -> aninda
    END AS [Gercek Tahsilat Tarihi],

    -- Islem tarihi ile gercek tahsilat arasindaki fark
    CASE
        WHEN ch.cha_cinsi IN (1, 2) THEN
            DATEDIFF(DAY, ch.cha_tarihi,
                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 CAST(ch.cha_tarihi AS date)
                END)
        ELSE 0
    END AS [Vade Gun Sayisi]

FROM CARI_HESAP_HAREKETLERI ch WITH (NOLOCK)
WHERE ch.cha_kod = @CariKod
  AND ch.cha_tip = 1          -- Alacak (tahsilat)
  AND ch.cha_iptal = 0
  AND ch.cha_meblag > 0
ORDER BY ch.cha_tarihi ASC;
```

### Beklenen Output

| İşlem Tarihi | cha_cinsi | Tahsilat Türü | Tutar | Gerçek Tahsilat | Vade Gün |
|---|---|---|---|---|---|
| 2026-01-15 | 1 | Müşteri Çeki | 45.000 | 2026-03-30 | 74 |
| 2026-02-20 | 0 | Nakit/Havale | 12.000 | 2026-02-20 | 0 |
| 2026-03-10 | 1 | Müşteri Çeki | 78.000 | 2026-06-15 | 97 |
| 2026-03-25 | 19 | Kredi Kartı | 5.500 | 2026-03-25 | 0 |

Çekler 74-97 günlük vadeyle alınmış. Nakit ve kredi kartı hareketlerinde vade 0 gün.

## SQL: Tahsilat Aracı Dağılımı Raporu (Tüm Cariler)

Hangi müşteriniz daha çok çekle, hangisi nakit ödüyor? Çek müşterilerinin ortalama vade günü nedir?

```sql
SELECT
    ch.cha_kod AS [Cari Kodu],
    c.cari_unvan1 AS [Musteri],

    -- Tahsilat araci bazinda tutarlar
    SUM(CASE WHEN ch.cha_cinsi NOT IN (1, 2, 19)
             THEN ch.cha_meblag ELSE 0 END)       AS [Nakit/Havale],
    SUM(CASE WHEN ch.cha_cinsi = 1
             THEN ch.cha_meblag ELSE 0 END)        AS [Cek Tutar],
    SUM(CASE WHEN ch.cha_cinsi = 2
             THEN ch.cha_meblag ELSE 0 END)        AS [Senet Tutar],
    SUM(CASE WHEN ch.cha_cinsi = 19
             THEN ch.cha_meblag ELSE 0 END)        AS [Kredi Karti],

    -- Toplam tahsilat
    SUM(ch.cha_meblag) AS [Toplam Tahsilat],

    -- Cek yuzdesi
    CONVERT(decimal(5,1),
    100.0 * SUM(CASE WHEN ch.cha_cinsi = 1 THEN ch.cha_meblag ELSE 0 END)
          / NULLIF(SUM(ch.cha_meblag), 0)) AS [Cek Yuzdesi %],

    -- Cek agirlikli ortalama vade gunu
    CASE WHEN SUM(CASE WHEN ch.cha_cinsi = 1 THEN ch.cha_meblag ELSE 0 END) > 0
        THEN
            SUM(CASE WHEN ch.cha_cinsi = 1 THEN
                ch.cha_meblag * DATEDIFF(DAY, ch.cha_tarihi,
                    CASE
                        WHEN ch.cha_vade BETWEEN 19000101 AND 20991231
                        THEN TRY_CONVERT(date, CONVERT(char(8), ch.cha_vade), 112)
                        ELSE CAST(ch.cha_tarihi AS date)
                    END)
                ELSE 0 END)
            / NULLIF(SUM(CASE WHEN ch.cha_cinsi = 1
                              THEN ch.cha_meblag ELSE 0 END), 0)
        ELSE NULL
    END AS [Cek Ort Vade Gun]

FROM CARI_HESAP_HAREKETLERI ch WITH (NOLOCK)
INNER JOIN CARI_HESAPLAR c WITH (NOLOCK)
    ON ch.cha_kod = c.cari_kod
WHERE ch.cha_tip = 1          -- Alacak (tahsilat)
  AND ch.cha_iptal = 0
  AND ch.cha_meblag > 0
GROUP BY ch.cha_kod, c.cari_unvan1
HAVING SUM(ch.cha_meblag) > 0
ORDER BY [Cek Tutar] DESC;
```

## İki Metrik Karşılaştırması: Toggle Yaklaşımı

Gerçek bir analiz sisteminde her iki tarihi de yan yana göstermelisiniz:

| Müşteri | Ort. Süre (İşlem) | Ort. Süre (Gerçek) | Fark |
|---|---|---|---|
| ABC Ltd. | 12 gün | 85 gün | **73 gün!** |
| XYZ A.Ş. | 8 gün | 8 gün | 0 gün |
| DEF Tic. | 22 gün | 45 gün | 23 gün |

ABC Ltd. her zaman çekle ödüyor — işlem tarihine bakarsanız "hızlı müşteri", gerçek tahsilata bakarsanız "90 günlük müşteri". Bu ayrım **nakit akışı planlaması** için kritiktir.

XYZ A.Ş. nakit ödüyor — iki metrik aynı. DEF Tic. karışık (nakit + çek).

## Nihai Tam Sorgu: Kopyala — Yapıştır — Çalıştır

Bir carinin tüm tahsilatlarını gerçek tahsilat tarihi, vade günü ve araç dağılımıyla birlikte gösterir:

```sql
-- =============================================
-- CEK/SENET GERCEK TAHSILAT TARIHI + ARAC DAGILIMI
-- Kullanim: @CariKod degistirin, F5 basin
-- Uyumluluk: SQL Server 2016+
-- =============================================
DECLARE @CariKod VARCHAR(50) = '120.001'; -- << BURAYA KENDI CARI KODUNUZU YAZIN

-- BOLUM 1: Detay listesi
SELECT
    CAST(ch.cha_tarihi AS date) AS [Islem Tarihi],
    CASE ch.cha_cinsi
        WHEN 0 THEN 'Nakit/Havale'
        WHEN 1 THEN 'Musteri Ceki'
        WHEN 2 THEN 'Musteri Senedi'
        WHEN 3 THEN 'Firma Ceki'
        WHEN 5 THEN 'Dekont'
        WHEN 19 THEN 'Kredi Karti'
        ELSE 'Diger (' + CAST(ch.cha_cinsi AS VARCHAR) + ')'
    END AS [Tahsilat Turu],
    ch.cha_meblag AS [Tutar],
    ch.cha_evrakno_seri + '-' + CAST(ch.cha_evrakno_sira AS VARCHAR) AS [Evrak No],
    CASE
        WHEN ch.cha_cinsi IN (1, 2) AND ch.cha_vade BETWEEN 19000101 AND 20991231
        THEN TRY_CONVERT(date, CONVERT(char(8), ch.cha_vade), 112)
        WHEN ch.cha_cinsi IN (1, 2) AND ch.cha_vade BETWEEN -36500 AND -1
        THEN DATEADD(DAY, ABS(ch.cha_vade), CAST(ch.cha_tarihi AS date))
        ELSE CAST(ch.cha_tarihi AS date)
    END AS [Gercek Tahsilat Tarihi],
    CASE
        WHEN ch.cha_cinsi IN (1, 2) THEN
            DATEDIFF(DAY, ch.cha_tarihi,
                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 CAST(ch.cha_tarihi AS date)
                END)
        ELSE 0
    END AS [Vade Gun Sayisi]
FROM CARI_HESAP_HAREKETLERI ch WITH (NOLOCK)
WHERE ch.cha_kod = @CariKod
  AND ch.cha_tip = 1 AND ch.cha_iptal = 0 AND ch.cha_meblag > 0
ORDER BY ch.cha_tarihi ASC;

-- BOLUM 2: Ozet dagilim
SELECT
    @CariKod AS [Cari Kodu],
    SUM(CASE WHEN cha_cinsi NOT IN (1,2,19) THEN cha_meblag ELSE 0 END) AS [Nakit/Havale],
    SUM(CASE WHEN cha_cinsi = 1 THEN cha_meblag ELSE 0 END) AS [Cek],
    SUM(CASE WHEN cha_cinsi = 2 THEN cha_meblag ELSE 0 END) AS [Senet],
    SUM(CASE WHEN cha_cinsi = 19 THEN cha_meblag ELSE 0 END) AS [Kredi Karti],
    SUM(cha_meblag) AS [Toplam],
    CONVERT(decimal(5,1),
        100.0 * SUM(CASE WHEN cha_cinsi IN (1,2) THEN cha_meblag ELSE 0 END)
              / NULLIF(SUM(cha_meblag), 0)) AS [Cek+Senet %]
FROM CARI_HESAP_HAREKETLERI WITH (NOLOCK)
WHERE cha_kod = @CariKod
  AND cha_tip = 1 AND cha_iptal = 0 AND cha_meblag > 0;
```

## Edge Cases (Dikkat Edilmesi Gerekenler)

### 1. cha_vade Boş veya Geçersiz Olabilir

Bazı çek hareketlerinde `cha_vade = 0` veya `NULL` olabilir. Bu durumda `cha_tarihi` kullanılır (yukarıdaki CASE ifadesinin ELSE dalı bunu karşılar).

### 2. Ciro Çekleri

Bir müşteri başka bir carinin çekini ciro edebilir. Bu durumda hareket `cha_ciro_cari_kodu` alanında ilgili cariye bağlıdır. WHERE koşuluna ek filtre gerekebilir:

```sql
WHERE (ch.cha_kod = @CariKod OR ch.cha_ciro_cari_kodu = @CariKod)
```

### 3. Karşılıksız Çekler

Çekin karşılıksız çıkması durumunda `cha_sntck_poz` alanı güncellenir:

| cha_sntck_poz | Durum |
|---|---|
| 0 | Portföyde |
| 1 | Ciro edildi |
| 2 | Tahsilde |
| 3 | Teminatta |
| 4 | İade edilen |
| 9 | Kısmen ödendi |
| 10 | Ödendi |

Karşılıksız çekler teminat olarak sayılmamalıdır. Risk analizinde `cha_sntck_poz` kontrolü yapılmalıdır.

### 4. Senet vs Çek Farkı

Muhasebe perspektifinden ikisi de vadeli ödeme araçlarıdır ancak:
- **Çek (cha_cinsi = 1):** Bankadan tahsil edilir, karşılıksız riski vardır
- **Senet (cha_cinsi = 2):** Protesto edilebilir, daha uzun vadeli olabilir

SQL sorgusunda ikisi de aynı mantıkla işlenir (her ikisi de `cha_vade` tarihinde tahsil edilir).

## İlgili Yazılar

- [Çek/Senet Vade Takip Raporu](/blog/mikro-erp-cek-senet-vade-takip-sql/)
- [cha_vade Hesaplama Rehberi](/blog/mikro-erp-vade-hesaplama-cha-vade-sql/)
- [Ortalama Tahsilat Süresi (DSO) Hesaplama](/blog/mikro-erp-ortalama-tahsilat-suresi-dso-sql/)
- [Tahsilat Detay Raporu](/blog/mikro-erp-cari-tahsilat-detay-raporu-sql/)
- [Cari Risk Raporu — Bakiye, Sipariş, Teminat](/blog/mikro-erp-cari-risk-raporu-sql/)
- [Vadesinde Ödeme Yüzdesi Analizi](/blog/mikro-erp-vadesinde-odeme-yuzdesi-sql/)

---

*Bu yazı [AstaFlow Case Study](/case-study) serisinin bir parçasıdır — çek/senet gerçek tahsilat tarihi ayrımı, ortalama tahsilat süresi ve risk analizi modüllerinde kritik bir karar noktası olarak karşımıza çıkmıştır.*