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ıf | Risk | Kredi Kararı |
|---|---|---|
| A | Çok Düşük | Vade uzatılabilir, limit artırılabilir |
| B | Düşük | Standart vade, limit yeterli |
| C | Orta | Yakın takip, teminat istenmeli |
| D | Yüksek | Vade kısaltılmalı, limit düşürülmeli |
| E | Çok Yüksek | Peş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şen | Ağırlık | Veri Kaynağı |
|---|---|---|
| Ortalama Tahsilat Süresi | %30 | FIFO parça ağırlıklı DSO |
| Vadesinde Ödeme Yüzdesi | %25 | FIFO parça bazlı vade analizi |
| Mevcut Bakiye / Limit Oranı | %20 | Bakiye vs teminat karşılaştırması |
| Bakiye Trend Yönü | %15 | Son 3 ay bakiye değişimi |
| Çek/Senet Risk Faktörü | %10 | Vadeli ö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 Kodu | Müşteri | Skor | Sınıf | Risk | Tahsilat | Vade | Limit | Trend | Çek |
|---|---|---|---|---|---|---|---|---|---|
| 120.004 | GHİ İnşaat | 94,5 | A | Çok Düşük | 100 | 98 | 100 | 75 | 100 |
| 120.001 | ABC Matbaa | 85,8 | A | Çok Düşük | 100 | 92 | 100 | 0 | 80 |
| 120.003 | DEF Gıda | 60,7 | B | Düşük | 63 | 71 | 50 | 100 | 60 |
| 120.002 | XYZ Ticaret | 30,4 | E | Çok Yüksek | 17 | 48 | 0 | 0 | 20 |
| 120.005 | JKL Tekstil | 20,5 | E | Çok Yüksek | 0 | 35 | 0 | 0 | 20 |
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” |
|---|---|---|---|
| Perakende | 0-15 gün | 15-30 gün | 30+ gün |
| Toptan | 0-45 gün | 45-90 gün | 90+ gün |
| İnşaat/Proje | 0-90 gün | 90-180 gün | 180+ 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:
#CariMetriklerINSERT 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
-
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.
-
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.
-
Grup şirketleri: Aynı grubun farklı tüzel kişilikleri varsa, grup bazlı konsolide skor hesaplanmalıdır.
-
Dövizli cariler: Bakiye ve limit karşılaştırmasında aynı döviz cinsi kullanılmalıdır.
İlgili Yazılar
- Cari Risk Raporu — Bakiye, Sipariş, Teminat
- Ortalama Tahsilat Süresi (DSO) Hesaplama
- Vadesinde Ödeme Yüzdesi Analizi
- Cari Yaşlandırma SQL Sorgusu — FIFO Bakiye Dağıtımı
- FIFO Fatura-Tahsilat Eşleştirme Algoritması
- Çek ve Senet Gerçek Tahsilat Tarihi
- fn_CariRiskFoyu Analizi
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.