Mikro ERP Cari Kredi Derecelendirme ve Risk Skorlama: Yaşlandırma Verileriyle Otomatik Sınıflandırma

Müşterilerinizi A-B-C-D-E risk sınıflarına otomatik ayırın. Ortalama tahsilat süresi, vadesinde ödeme yüzdesi, bakiye trendi ve çek riski bileşenleriyle SQL tabanlı kredi derecelendirme modeli.

Neden Otomatik Derecelendirme?

“Bu müşteriye daha fazla vadeli satış yapabilir miyiz?” sorusunu her defasında bir kişinin tecrübesine bırakmak ölçeklenebilir değildir. 500+ müşteriniz varsa, her birini tek tek incelemek imkânsızdır.

Otomatik derecelendirme ERP verilerinden hesaplanan metriklerle müşterilerinizi risk sınıflarına ayırır:

SınıfRiskKredi Kararı
AÇok DüşükVade uzatılabilir, limit artırılabilir
BDüşükStandart vade, limit yeterli
COrtaYakın takip, teminat istenmeli
DYüksekVade kısaltılmalı, limit düşürülmeli
EÇok YüksekPeşin satış veya satış durdurma

Skor Bileşenleri ve Ağırlıkları

Kredi skoru 5 bileşenden oluşur. Her bileşen 0-100 arası puan alır, sonra ağırlıkla çarpılır:

BileşenAğırlıkVeri Kaynağı
Ortalama Tahsilat Süresi%30FIFO parça ağırlıklı DSO
Vadesinde Ödeme Yüzdesi%25FIFO parça bazlı vade analizi
Mevcut Bakiye / Limit Oranı%20Bakiye vs teminat karşılaştırması
Bakiye Trend Yönü%15Son 3 ay bakiye değişimi
Çek/Senet Risk Faktörü%10Vadeli ödeme aracı oranı

Adım 1: Test Verisi ile Skorlama (Mikro ERP Gerekmez)

Önce konsepti anlamak için test verisi ile çalışalım:

-- =============================================
-- TEST VERISI - Kendi DB'nizde calistirabilirsiniz
-- =============================================
IF OBJECT_ID('tempdb..#CariMetrikler') IS NOT NULL DROP TABLE #CariMetrikler;

CREATE TABLE #CariMetrikler (
    CariKod VARCHAR(50),
    CariAd VARCHAR(200),
    OrtTahsilatGun DECIMAL(10,1),      -- Ort. tahsilat suresi (gun)
    VadesindeOdemeYuzde DECIMAL(5,1),  -- Vadesinde odeme %
    MevcutBakiye DECIMAL(18,2),        -- Acik bakiye
    KrediLimiti DECIMAL(18,2),         -- Teminat/limit
    BakiyeOncekiAy DECIMAL(18,2),      -- Onceki ay bakiye
    BakiyeIkiAyOnce DECIMAL(18,2),     -- 2 ay onceki bakiye
    CekOrani DECIMAL(5,1)              -- Toplam tahsilatta cek yuzdesi
);

INSERT INTO #CariMetrikler VALUES
    ('120.001', 'ABC Matbaa Ltd.', 28.5, 92.0, 45000, 100000, 42000, 38000, 15.0),
    ('120.002', 'XYZ Ticaret A.S.', 65.3, 48.0, 180000, 50000, 150000, 120000, 85.0),
    ('120.003', 'DEF Gida San.', 42.0, 71.0, 95000, 80000, 100000, 110000, 45.0),
    ('120.004', 'GHI Insaat', 15.2, 98.0, 12000, 200000, 15000, 10000, 0.0),
    ('120.005', 'JKL Tekstil', 88.7, 35.0, 250000, 30000, 200000, 160000, 92.0);

Adım 2: Her Bileşenin Puanlanması

;WITH Puanlama AS (
    SELECT
        CariKod,
        CariAd,
        OrtTahsilatGun,
        VadesindeOdemeYuzde,
        MevcutBakiye,
        KrediLimiti,

        -- BILESEN 1: Ort. Tahsilat Suresi Puani (0-100)
        -- 0-30 gun = 100, 30-60 gun = 75, 60-90 gun = 50, 90-120 gun = 25, 120+ = 0
        CASE
            WHEN OrtTahsilatGun <= 30 THEN 100
            WHEN OrtTahsilatGun <= 60 THEN 100 - ((OrtTahsilatGun - 30) * 100.0 / 90)
            WHEN OrtTahsilatGun <= 90 THEN 50 - ((OrtTahsilatGun - 60) * 50.0 / 60)
            WHEN OrtTahsilatGun <= 120 THEN 25 - ((OrtTahsilatGun - 90) * 25.0 / 30)
            ELSE 0
        END AS TahsilatPuan,

        -- BILESEN 2: Vadesinde Odeme Puani (0-100)
        -- Direkt yuzde degeri kullanilir
        VadesindeOdemeYuzde AS VadePuan,

        -- BILESEN 3: Bakiye/Limit Orani Puani (0-100)
        -- Bakiye < %50 limit = 100, %50-80 = 75, %80-100 = 50, %100-150 = 25, >%150 = 0
        CASE
            WHEN KrediLimiti = 0 THEN 0  -- Limitsiz = en riskli
            WHEN MevcutBakiye / KrediLimiti <= 0.5 THEN 100
            WHEN MevcutBakiye / KrediLimiti <= 0.8 THEN 75
            WHEN MevcutBakiye / KrediLimiti <= 1.0 THEN 50
            WHEN MevcutBakiye / KrediLimiti <= 1.5 THEN 25
            ELSE 0
        END AS LimitPuan,

        -- BILESEN 4: Bakiye Trend Puani (0-100)
        -- Bakiye azaliyorsa iyi (100), artiyorsa kotu (0)
        CASE
            WHEN MevcutBakiye < BakiyeIkiAyOnce THEN 100  -- Azaliyor: iyi
            WHEN MevcutBakiye = BakiyeIkiAyOnce THEN 75   -- Sabit: orta
            WHEN MevcutBakiye < BakiyeIkiAyOnce * 1.2 THEN 50  -- Hafif artiyor
            WHEN MevcutBakiye < BakiyeIkiAyOnce * 1.5 THEN 25  -- Belirgin artiyor
            ELSE 0                                               -- Hizla artiyor
        END AS TrendPuan,

        -- BILESEN 5: Cek Riski Puani (0-100)
        -- Dusuk cek orani = yuksek puan
        CASE
            WHEN CekOrani <= 20 THEN 100   -- Cogunlukla nakit
            WHEN CekOrani <= 40 THEN 80
            WHEN CekOrani <= 60 THEN 60
            WHEN CekOrani <= 80 THEN 40
            ELSE 20                         -- Cogunlukla cek = riskli
        END AS CekPuan

    FROM #CariMetrikler
),

-- AGIRLIKLI SKOR HESAPLAMA
Skorlama AS (
    SELECT
        CariKod,
        CariAd,
        OrtTahsilatGun,
        VadesindeOdemeYuzde,
        MevcutBakiye,
        KrediLimiti,
        TahsilatPuan,
        VadePuan,
        LimitPuan,
        TrendPuan,
        CekPuan,

        -- TOPLAM SKOR (agirlikli ortalama)
        CONVERT(decimal(5,1),
            TahsilatPuan * 0.30       -- %30
          + VadePuan * 0.25           -- %25
          + LimitPuan * 0.20          -- %20
          + TrendPuan * 0.15          -- %15
          + CekPuan * 0.10            -- %10
        ) AS ToplamSkor
    FROM Puanlama
)

-- SINIFLANDIRMA
SELECT
    CariKod AS [Cari Kodu],
    CariAd AS [Musteri],
    ToplamSkor AS [Kredi Skoru],
    CASE
        WHEN ToplamSkor >= 80 THEN 'A'
        WHEN ToplamSkor >= 65 THEN 'B'
        WHEN ToplamSkor >= 50 THEN 'C'
        WHEN ToplamSkor >= 35 THEN 'D'
        ELSE 'E'
    END AS [Risk Sinifi],
    CASE
        WHEN ToplamSkor >= 80 THEN 'Cok Dusuk Risk'
        WHEN ToplamSkor >= 65 THEN 'Dusuk Risk'
        WHEN ToplamSkor >= 50 THEN 'Orta Risk'
        WHEN ToplamSkor >= 35 THEN 'Yuksek Risk'
        ELSE 'Cok Yuksek Risk'
    END AS [Risk Durumu],

    -- Bilesen detaylari
    TahsilatPuan AS [Tahsilat Puan],
    VadePuan AS [Vade Puan],
    LimitPuan AS [Limit Puan],
    TrendPuan AS [Trend Puan],
    CekPuan AS [Cek Puan],

    -- Ek bilgiler
    CONVERT(VARCHAR, OrtTahsilatGun) + ' gun' AS [Ort Tahsilat],
    CONVERT(VARCHAR, CONVERT(int, VadesindeOdemeYuzde)) + '%' AS [Vadesinde %],
    CONVERT(VARCHAR, CONVERT(int, MevcutBakiye)) + ' / '
        + CONVERT(VARCHAR, CONVERT(int, KrediLimiti)) AS [Bakiye/Limit]

FROM Skorlama
ORDER BY ToplamSkor DESC;

Beklenen Output

Cari KoduMüşteriSkorSınıfRiskTahsilatVadeLimitTrendÇek
120.004GHİ İnşaat94,5AÇok Düşük1009810075100
120.001ABC Matbaa85,8AÇok Düşük10092100080
120.003DEF Gıda60,7BDüşük63715010060
120.002XYZ Ticaret30,4EÇok Yüksek17480020
120.005JKL Tekstil20,5EÇok Yüksek0350020

Adım 3: Mikro ERP Tabloları ile Gerçek Veri

Test verisini anladıysanız, gerçek Mikro ERP verilerinden metrikleri çekmek için şu tabloları kullanın:

-- Gercek Mikro ERP verisi ile metrik hesaplama
;WITH CariBakiye AS (
    SELECT
        cha_kod AS CariKod,
        SUM(CASE WHEN cha_tip = 0 THEN cha_meblag ELSE -cha_meblag END) AS MevcutBakiye
    FROM CARI_HESAP_HAREKETLERI WITH (NOLOCK)
    WHERE cha_iptal = 0
    GROUP BY cha_kod
    HAVING SUM(CASE WHEN cha_tip = 0 THEN cha_meblag ELSE -cha_meblag END) > 0
),
CariTeminat AS (
    SELECT
        ct_carikodu AS CariKod,
        SUM(ct_tutari) AS KrediLimiti
    FROM CARI_HESAP_TEMINATLARI WITH (NOLOCK)
    WHERE ISNULL(ct_iptal, 0) = 0
    GROUP BY ct_carikodu
),
TahsilatAraci AS (
    SELECT
        cha_kod AS CariKod,
        -- Cek yuzdesi
        100.0 * SUM(CASE WHEN cha_cinsi = 1 THEN cha_meblag ELSE 0 END)
              / NULLIF(SUM(cha_meblag), 0) AS CekOrani
    FROM CARI_HESAP_HAREKETLERI WITH (NOLOCK)
    WHERE cha_tip = 1 AND cha_iptal = 0 AND cha_meblag > 0
    GROUP BY cha_kod
)

SELECT
    cb.CariKod,
    c.cari_unvan1 AS CariAd,
    cb.MevcutBakiye,
    ISNULL(ct.KrediLimiti, 0) AS KrediLimiti,
    ISNULL(ta.CekOrani, 0) AS CekOrani
    -- OrtTahsilatGun ve VadesindeOdemeYuzde icin
    -- ayri FIFO hesaplama gerekir (ilgili yazilara bakin)
FROM CariBakiye cb
INNER JOIN CARI_HESAPLAR c WITH (NOLOCK) ON cb.CariKod = c.cari_kod
LEFT JOIN CariTeminat ct ON cb.CariKod = ct.CariKod
LEFT JOIN TahsilatAraci ta ON cb.CariKod = ta.CariKod
ORDER BY cb.MevcutBakiye DESC;

Not: Ortalama tahsilat süresi ve vadesinde ödeme yüzdesi için FIFO parça bazlı hesaplama gerekir. Detaylar:

Skor Bantlarını Özelleştirme

Yukarıdaki eşik değerleri ve ağırlıklar bir başlangıç noktasıdır. Kendi işletmenize göre ayarlamanız gereken parametreler:

Tahsilat Süresi Eşikleri

Sektör”İyi""Kabul Edilebilir""Riskli”
Perakende0-15 gün15-30 gün30+ gün
Toptan0-45 gün45-90 gün90+ gün
İnşaat/Proje0-90 gün90-180 gün180+ gün

Ağırlıkları Değiştirme

-- Sektorunuze gore agirliklari degistirin
-- Toptan ticaret icin tahsilat suresi daha onemli:
TahsilatPuan * 0.35    -- %30 -> %35
VadePuan * 0.25        -- ayni
LimitPuan * 0.20       -- ayni
TrendPuan * 0.10       -- %15 -> %10
CekPuan * 0.10         -- ayni
-- Toplam: %100

Kredi Limit Önerisi

Skor bazlı otomatik kredi limit önerisi:

-- Risk sinifina gore limit carpani
SELECT
    CariKod,
    CariAd,
    ToplamSkor,
    CASE
        WHEN ToplamSkor >= 80 THEN 'A'
        WHEN ToplamSkor >= 65 THEN 'B'
        WHEN ToplamSkor >= 50 THEN 'C'
        WHEN ToplamSkor >= 35 THEN 'D'
        ELSE 'E'
    END AS Sinif,

    -- Aylik ortalama satis
    MevcutBakiye AS [Mevcut Bakiye],

    -- Onerilen limit (risk sinifina gore carpan)
    CASE
        WHEN ToplamSkor >= 80 THEN MevcutBakiye * 3.0   -- A: 3 aylik
        WHEN ToplamSkor >= 65 THEN MevcutBakiye * 2.0   -- B: 2 aylik
        WHEN ToplamSkor >= 50 THEN MevcutBakiye * 1.0   -- C: 1 aylik
        WHEN ToplamSkor >= 35 THEN MevcutBakiye * 0.5   -- D: yarim aylik
        ELSE 0                                            -- E: limit yok
    END AS [Onerilen Limit]

FROM Skorlama
ORDER BY ToplamSkor DESC;

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

Test verisi dahil — herhangi bir SQL Server’da çalışır, Mikro ERP gerekmez:

-- =============================================
-- CARI KREDI DERECELENDIRME VE SKORLAMA
-- Kullanim: Direkt F5 basin, sonuc gelir
-- Test verisi dahil, Mikro ERP gerekmez
-- Uyumluluk: SQL Server 2016+
-- =============================================

-- TEST VERISI
IF OBJECT_ID('tempdb..#CariMetrikler') IS NOT NULL DROP TABLE #CariMetrikler;

CREATE TABLE #CariMetrikler (
    CariKod VARCHAR(50), CariAd VARCHAR(200),
    OrtTahsilatGun DECIMAL(10,1), VadesindeOdemeYuzde DECIMAL(5,1),
    MevcutBakiye DECIMAL(18,2), KrediLimiti DECIMAL(18,2),
    BakiyeOncekiAy DECIMAL(18,2), BakiyeIkiAyOnce DECIMAL(18,2),
    CekOrani DECIMAL(5,1)
);

INSERT INTO #CariMetrikler VALUES
    ('120.001', 'ABC Matbaa Ltd.',    28.5, 92.0, 45000,  100000, 42000,  38000,  15.0),
    ('120.002', 'XYZ Ticaret A.S.',   65.3, 48.0, 180000,  50000, 150000, 120000, 85.0),
    ('120.003', 'DEF Gida San.',      42.0, 71.0, 95000,   80000, 100000, 110000, 45.0),
    ('120.004', 'GHI Insaat',         15.2, 98.0, 12000,  200000, 15000,  10000,   0.0),
    ('120.005', 'JKL Tekstil',        88.7, 35.0, 250000,  30000, 200000, 160000, 92.0);

-- PUANLAMA + SINIFLANDIRMA
;WITH Skorlama AS (
    SELECT *,
        -- Tahsilat suresi puani (0-100)
        CASE WHEN OrtTahsilatGun <= 30 THEN 100
             WHEN OrtTahsilatGun <= 60 THEN 100 - ((OrtTahsilatGun-30) * 100.0/90)
             WHEN OrtTahsilatGun <= 90 THEN 50 - ((OrtTahsilatGun-60) * 50.0/60)
             ELSE 0 END AS P1,
        -- Vadesinde odeme puani
        VadesindeOdemeYuzde AS P2,
        -- Bakiye/limit puani
        CASE WHEN KrediLimiti = 0 THEN 0
             WHEN MevcutBakiye/KrediLimiti <= 0.5 THEN 100
             WHEN MevcutBakiye/KrediLimiti <= 0.8 THEN 75
             WHEN MevcutBakiye/KrediLimiti <= 1.0 THEN 50
             WHEN MevcutBakiye/KrediLimiti <= 1.5 THEN 25
             ELSE 0 END AS P3,
        -- Trend puani
        CASE WHEN MevcutBakiye < BakiyeIkiAyOnce THEN 100
             WHEN MevcutBakiye = BakiyeIkiAyOnce THEN 75
             WHEN MevcutBakiye < BakiyeIkiAyOnce * 1.2 THEN 50
             WHEN MevcutBakiye < BakiyeIkiAyOnce * 1.5 THEN 25
             ELSE 0 END AS P4,
        -- Cek risk puani
        CASE WHEN CekOrani <= 20 THEN 100 WHEN CekOrani <= 40 THEN 80
             WHEN CekOrani <= 60 THEN 60 WHEN CekOrani <= 80 THEN 40
             ELSE 20 END AS P5
    FROM #CariMetrikler
)

SELECT
    CariKod AS [Cari Kodu],
    CariAd AS [Musteri],
    CONVERT(decimal(5,1), P1*0.30 + P2*0.25 + P3*0.20 + P4*0.15 + P5*0.10) AS [Kredi Skoru],
    CASE
        WHEN P1*0.30+P2*0.25+P3*0.20+P4*0.15+P5*0.10 >= 80 THEN 'A - Cok Dusuk Risk'
        WHEN P1*0.30+P2*0.25+P3*0.20+P4*0.15+P5*0.10 >= 65 THEN 'B - Dusuk Risk'
        WHEN P1*0.30+P2*0.25+P3*0.20+P4*0.15+P5*0.10 >= 50 THEN 'C - Orta Risk'
        WHEN P1*0.30+P2*0.25+P3*0.20+P4*0.15+P5*0.10 >= 35 THEN 'D - Yuksek Risk'
        ELSE 'E - Cok Yuksek Risk'
    END AS [Risk Sinifi],
    CONVERT(int, P1) AS [Tahsilat], CONVERT(int, P2) AS [Vade],
    CONVERT(int, P3) AS [Limit], CONVERT(int, P4) AS [Trend], CONVERT(int, P5) AS [Cek],
    CONVERT(VARCHAR, OrtTahsilatGun) + ' gun' AS [Ort Tahsilat],
    CONVERT(VARCHAR, CONVERT(int, VadesindeOdemeYuzde)) + '%' AS [Vadesinde %],
    CONVERT(VARCHAR, CONVERT(int, MevcutBakiye)) + ' / '
        + CONVERT(VARCHAR, CONVERT(int, KrediLimiti)) AS [Bakiye/Limit]
FROM Skorlama
ORDER BY (P1*0.30 + P2*0.25 + P3*0.20 + P4*0.15 + P5*0.10) DESC;

DROP TABLE #CariMetrikler;

Kendi verilerinizle kullanmak için: #CariMetrikler INSERT satırlarını Mikro ERP’den çektiğiniz gerçek metriklerle değiştirin. Metriklerin nasıl hesaplandığını DSO ve Vadesinde Ödeme yazılarında bulabilirsiniz.

Edge Cases

  1. Yeni müşteriler: Yeterli geçmiş verisi olmayan müşteriler için varsayılan olarak C sınıfı (orta risk) atanabilir. 3 aylık veri biriktiğinde otomatik derecelendirme devreye girer.

  2. Mevsimsel müşteriler: Tarım veya turizm sektöründe sezonluk alım yapan müşteriler için bakiye trend bileşeni yanıltıcı olabilir. Son 12 ay ortalaması daha sağlıklıdır.

  3. Grup şirketleri: Aynı grubun farklı tüzel kişilikleri varsa, grup bazlı konsolide skor hesaplanmalıdır.

  4. Dövizli cariler: Bakiye ve limit karşılaştırmasında aynı döviz cinsi kullanılmalıdır.

İlgili Yazılar


Bu yazı AstaFlow Case Study serisinin bir parçasıdır — cari derecelendirme skoru, yaşlandırma ve tahsilat modüllerinden elde edilen verileri tek bir karar destek metriğinde birleştirir.

📚 İlgili Yazılar