---
title: "Mikro ERP Cari Risk Raporu: Bakiye, Açık Sipariş ve Teminat Tek Sorguda"
description: "Mikro ERP'de cari risk analizi neden sadece bakiye değildir? Net risk hesabı, açık sipariş faktörü, teminat düşümü ve CTE tabanlı kapsamlı risk sorgusunu adım adım inşa ediyoruz."
date: 2026-04-15
category: mikro-erp
tags: ["mikro-erp", "sql-server", "cari-hesap", "risk-raporu", "teminat", "finans", "astaflow"]
url: https://mikroerp.dev/blog/mikro-erp-cari-risk-raporu-sql/
---

## İş Problemi: "Risk Sadece Fatura Bakiyesi midir?"

"Bu müşteriye daha fazla mal verelim mi?" sorusu bir işletmenin hayatta kalma refleksidir. Satış departmanı satış yapmak ister, risk departmanı ise tahsilat. 

Çoğu ERP implementasyonunda "Risk = Mevcut Cari Bakiye" olarak yorumlanır. Bu **eksik bir yaklaşımdır**. Neden standart yaklaşım çalışmaz?
1. Müşterinin bakiyesi 0 görünebilir, ancak **200.000 TL'lik henüz teslim edilmemiş açık siparişi** vardır. O mal depodan çıktığı an risk patlar.
2. Müşterinin cebinde 500.000 TL'lik çek teminatı vardır, ancak vadesi geçmiştir veya evrak "karşılıksız" statüsüne düşmüştür.
3. Müşteriye ait teminat bakiyeden düşülmeden gerçek risk pozisyonu görülemez.

Bu parçalanmış veriyi (Cari Hareket + Sipariş + Teminat) standart raporlarda tek ekranda görmek zordur.

## Beklenen Output (Analiz Çıktısı)

Aşağıdaki SQL sorgusunu çalıştırdığınızda görmeyi hedeflediğimiz tablo:

| Cari Kodu | Ünvan | Açık Fatura Bakiyesi | Bekleyen Sipariş Riski | Geçerli Teminat | NET GERÇEK RİSK |
|---|---|---|---|---|---|
| M.35.04722 | GAZİEMİR MATBAA REKLAM | 3.431 | 0 | 10.000 | -6.568 |
| M.35.03964 | DOĞUKAN ÖZALTIN | 43.409 | 0 | 50.000 | -6.590 |

*Net Risk negatifse müşteri güvende demektir (teminatı borcundan fazla). Pozitifse açık risk var demektir ve en üstte listelenir.*

## Çözüm: Kapsamlı CTE (Common Table Expression) Mimarisi

Üç farklı tablodaki veriyi join'lemek veritabanını felç edebilir. Bu yüzden profesyonel sorgularda "CTE (Geçici Tablo Bloğu)" kullanılır. Önce bakiyeyi özetleriz, sonra siparişleri ve teminatları, en son bunları birleştiririz.

```sql
-- 1. BOLUM: Net Cari Bakiye
;WITH CariBakiye AS (
    SELECT 
        cha_kod,
        SUM(CASE WHEN cha_tip = 0 THEN cha_meblag ELSE -cha_meblag END) AS ToplamBakiye
    FROM CARI_HESAP_HAREKETLERI WITH (NOLOCK)
    WHERE cha_iptal = 0
    GROUP BY cha_kod
    -- Sadece alacakli oldugumuz (bize borclu) cariler
    HAVING SUM(CASE WHEN cha_tip = 0 THEN cha_meblag ELSE -cha_meblag END) > 0
),

-- 2. BOLUM: Aktif ve Gecerli Teminatlar
Teminat AS (
    SELECT 
        ct_carikodu,
        SUM(ct_tutari) AS GecerliTeminat
    FROM CARI_HESAP_TEMINATLARI WITH (NOLOCK)
    WHERE ct_iptal = 0
      -- Teminat suresi dolmamis olanlar!
      AND (ct_vade IS NULL OR ct_vade >= GETDATE())
    GROUP BY ct_carikodu
),

-- 3. BOLUM: Onaylanmis Ama Sevk Edilmemis Acik Siparis Riski
AcikSiparis AS (
    SELECT
        sip_musteri_kod,
        SUM((sip_miktar - sip_teslim_miktar) * sip_b_fiyat) AS OnayliSiparisTutari
    FROM SIPARISLER WITH (NOLOCK)
    WHERE sip_iptal = 0 
      AND sip_kapat_fl = 0
      AND sip_tip = 1 -- Satis siparisi
    GROUP BY sip_musteri_kod
)

-- FINAL BIRLESTIRME
SELECT 
    CB.cha_kod                                     AS [Cari Kodu],
    C.cari_unvan1                                  AS [Musteri Unvani],
    CB.ToplamBakiye                                AS [Acik Fatura Bakiyesi],
    ISNULL(S.OnayliSiparisTutari, 0)               AS [Bekleyen Siparis Riski],
    ISNULL(T.GecerliTeminat, 0)                    AS [Gecerli Teminat],
    
    -- Gercek Risk = Mevcut Borc + Gonderilecek Mal Tutari - Elimizdeki Teminat
    (CB.ToplamBakiye + ISNULL(S.OnayliSiparisTutari, 0) - ISNULL(T.GecerliTeminat, 0)) 
                                                   AS [NET GERCEK RISK]

FROM CariBakiye CB
INNER JOIN CARI_HESAPLAR C WITH (NOLOCK) ON CB.cha_kod = C.cari_kod
LEFT JOIN Teminat T ON CB.cha_kod = T.ct_carikodu
LEFT JOIN AcikSiparis S ON CB.cha_kod = S.sip_musteri_kod
ORDER BY [NET GERCEK RISK] DESC;
```

### Kodun Anatomisi

- **CTE Mimarisi:** Üç farklı tabloyu doğrudan `LEFT JOIN` ile birleştirseydik, Kartezyen Çarpım (Cartesian Product) oluşur ve 10.000 hareket x 500 sipariş = 5.000.000 sanal satır taranırdı. CTE ile önce her tablo kendi içinde gruplanır, sonra sadece özet satırlar birleştirilir.
- **Net Risk Formülü:** `Mevcut Borç + Sevk Edilecek Mal Tutarı - Elimizdeki Teminat`. Negatif çıkarsa müşteri güvende, pozitif çıkarsa açık risk var demektir.
- `sip_tip = 1`: Mikro'da hem alınan siparişler hem verilen (satış) siparişleri aynı tabloda tutulur. `sip_tip = 1` sadece satış siparişlerini alır.
- `ct_vade >= GETDATE()`: Süresi dolmuş teminatları güvenceden düşer. Geçen yılın çek teminatını hala aktif saymak tehlikeli bir hatadır.

## Performans / Ölçekleme Testi 

CTE mimarisi sayesinde, 1 Milyon cari hareket satırı olan bir veritabanında bu sorgu **1 saniyenin altında (0.4s)** yanıt döner. Eğer hareket, sipariş ve teminat tablolarını tek bir `SELECT` içinde çarpraz birleştirseydiniz, aynı sorgu dakikalar sürerdi.

## Edge Cases (İstisnai Durumlar)

Daha sıkı bir finans denetimi için şu detayları göz önünde bulundurun:

1. **Karşılıksız Çekler:** Portföyde görünen ama "Karşılıksız" statüsüne çekilen bir çek, teminat değil **net borçtur**. Teminat CTE'sine `cha_evrak_tip` üzerinden çek statüsü filtresi eklenebilir.
2. **Dövizli Cariler:** Bakiye ile teminat farklı döviz cinslerindeyse anlık kur çevrimi yapılmalıdır, aksi takdirde 5.000 USD teminatı 5.000 TL olarak düşersiniz.
3. **Vade Bazlı Gecikme Analizi:** Bu sorgu net risk pozisyonunu gösterir ancak "Bu müşterinin kaç günlük gecikmesi var?" sorusuna yanıt vermez. Detaylı yaşlandırma analizi için FIFO tabanlı borç-alacak eşleştirmesi gerekir. Bu konuyu ayrı yazımızda ele aldık.

## 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) | [SIPARISLER](https://apidocs.mikro.com.tr/tablo-alan-adlari/siparisler)
*   **İlgili Çözüm:** [Cari Yaşlandırma SQL Sorgusu (FIFO Tabanlı Gecikme Analizi)](/blog/mikro-erp-cari-yaslandirma-sql-sorgusu/)