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:
- Yavaş. Geniş tarih aralığı ve çok sayıda cari için ciddi süre alıyor.
- 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:
-- İ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_vadeancak 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ü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ü
-- Ç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
-- =============================================
-- ⚙️ 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:
- Mikro ekranından bir cari seçin ve hareket föyünü açın.
- Aynı tarih aralığında SQL sorgunuzu çalıştırın.
- 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
- Mikro ERP DB API: CARI_HESAP_HAREKETLERI | CARI_HESAPLAR
- İlgili Yazı: Cari Ekstre Raporu SQL Sorgusu — Tüm cari hareketlerin detaylı dökümü
- İlgili Yazı: Çek/Senet Vade Takip Raporu — Çek ve senet pozisyonlarının vade bazlı analizi
- İlgili Yazı: Kapanmamış Cari Hareket Raporu — Açık kalan tahsilatların takibi
- İlgili Yazı: Kasa ve Nakit Akış Raporu — Kasa bazlı nakit giriş/çıkış analizi
- İlgili Araç: Evrak Tipi Decoder — cha_evrak_tip değerlerini anında çevirin