ERP Asistanı Dal Net
Netsis SQL

Netsis Cari Kârlılık SQL: Müşteri Bazında Brüt Kâr ve Marj

Netsis'te TBLSTHAR, TBLSTSABIT ve TBLCASABIT tablolarını birleştirerek cari bazında net ciro, satılan malın maliyeti ve brüt marjı hesaplayan hazır SQL sorguları.

Erp Asistanı Erp Asistanı Editör ekibi 12 dk okuma
Netsis Cari Kârlılık SQL: Müşteri Bazında Brüt Kâr ve Marj

Bir müşterinin cirosu büyükse iş hacmi büyüktür; kârı büyükse o iş size kalıyordur. Netsis'te bu iki rakamı yan yana görmek kolay değil: satış tutarı TBLSTHAR kalemlerinde durur, maliyet ise stok kartında (TBLSTSABIT) ya da alış hareketlerinde saklıdır. Cari unvanı da TBLCASABIT tablosundan gelir. Bu yazıda üç tabloyu birleştirip cari bazında net ciro, satılan malın maliyeti, brüt kâr ve marj üreten çalışır sorguları veriyorum. Sonunda asıl soruya geliyoruz: ciro lideri olup kâr bırakmayan müşteri hangisi?

Raporun mantığı: üç tablo, iki kritik kolon

Tablo ilişkilerine hâkim değilseniz önce Netsis tablo yapısı rehberine göz atın. Kârlılık raporunda kullanacağımız alanların tamamı şu dört tablodan geliyor:

Ne lazım Nereden Kolon Not
Satış tutarı TBLSTHAR STHAR_GCMIK * STHAR_NF Tutar satırda tutulmaz, hesaplanır. STHAR_NF KDV ve iskonto sonrası net birim fiyattır
Maliyet (hızlı yol) TBLSTSABIT ALIS_FIAT1 Kart üstündeki güncel alış fiyatı; geçmiş dönemi birebir yansıtmaz
Maliyet (dönemsel) TBLSTHAR STHAR_GCMIK, STHAR_NF Alış hareketlerinden ağırlıklı ortalama
Müşteri TBLCASABIT CARI_KOD, CARI_ISIM STHAR_CARIKOD ile birleşir
Yön TBLSTHAR STHAR_GCKOD C çıkış (satış), G giriş (iade)
Belge tipi TBLSTHAR STHAR_FTIRSIP Satış faturası 1, satış irsaliyesi 3

İki kritik kolon var. Birincisi STHAR_FTIRSIP: bu filtre olmadan alış, transfer ve irsaliye satırları satış gibi toplanır. İkincisi STHAR_GCKOD: iade edilen mal stok girişi (G) olarak yazılır; yön ayrımı yapılmazsa iadeler ciroyu ve maliyeti şişirir. Çok şubeli kurulumda SUBE_KODU filtresini de unutmayın.

1. Cari bazında net ciro, maliyet ve brüt marj

Aşağıdaki sorgu tek dönem için cari kârlılık tablosunu üretir. İade satırları CASE ile negatife çevrildiği için net ciro ve net maliyet doğru çıkar.

SELECT t.CariKod, t.CariUnvan, t.NetCiro, t.Maliyet, t.BrutKar,
       CAST(t.BrutKar / NULLIF(t.NetCiro, 0) * 100 AS decimal(9,2)) AS MarjYuzde
FROM (
    SELECT s.STHAR_CARIKOD AS CariKod,
           c.CARI_ISIM AS CariUnvan,
           SUM(CASE WHEN s.STHAR_GCKOD = 'C' THEN s.STHAR_GCMIK * s.STHAR_NF
                    ELSE -s.STHAR_GCMIK * s.STHAR_NF END) AS NetCiro,
           SUM(CASE WHEN s.STHAR_GCKOD = 'C' THEN s.STHAR_GCMIK * st.ALIS_FIAT1
                    ELSE -s.STHAR_GCMIK * st.ALIS_FIAT1 END) AS Maliyet,
           SUM(CASE WHEN s.STHAR_GCKOD = 'C' THEN s.STHAR_GCMIK * (s.STHAR_NF - st.ALIS_FIAT1)
                    ELSE -s.STHAR_GCMIK * (s.STHAR_NF - st.ALIS_FIAT1) END) AS BrutKar
    FROM TBLSTHAR s
    INNER JOIN TBLSTSABIT st ON st.STOK_KODU = s.STOK_KODU
    LEFT JOIN TBLCASABIT c ON c.CARI_KOD = s.STHAR_CARIKOD
    WHERE s.STHAR_FTIRSIP IN ('1','3')
      AND s.STHAR_TARIH >= '20260101'
      AND s.STHAR_TARIH < '20260701'
      AND s.SUBE_KODU = 0
    GROUP BY s.STHAR_CARIKOD, c.CARI_ISIM
) t
ORDER BY t.NetCiro DESC;

Bu raporu SQL yazmadan, Türkçe sorarak alın: Netsis raporlama

NULLIF marj bölmesinde sıfıra bölme hatasını engeller; iade fazlası olan caride net ciro negatife düşerse marj yorumu anlamsızlaşır, o satırları rapor dışında tutun.

2. Maliyeti alış hareketlerinden almak: ağırlıklı ortalama

ALIS_FIAT1 kart üstündeki güncel fiyattır. Tedarikçi zammı sonrası geçmiş ayların marjı olduğundan yüksek görünür. Dönemsel maliyet istiyorsanız alış faturası kalemlerinden ağırlıklı ortalama çıkarın. Mantık şu: alış miktarı çarpı net fiyat toplamı bölü toplam alış miktarı. Fiyat sapmasını takip etmek için alış fiyat sapması yazısına da bakabilirsiniz.

WITH Maliyet AS (
    SELECT STOK_KODU,
           SUM(STHAR_GCMIK * STHAR_NF) / NULLIF(SUM(STHAR_GCMIK), 0) AS OrtBirimMaliyet
    FROM TBLSTHAR
    WHERE STHAR_GCKOD = 'G'
      AND STHAR_FTIRSIP = '2'
      AND STHAR_TARIH < '20260701'
      AND SUBE_KODU = 0
    GROUP BY STOK_KODU
)
SELECT s.STHAR_CARIKOD AS CariKod,
       c.CARI_ISIM AS CariUnvan,
       SUM(CASE WHEN s.STHAR_GCKOD = 'C' THEN s.STHAR_GCMIK * s.STHAR_NF
                ELSE -s.STHAR_GCMIK * s.STHAR_NF END) AS NetCiro,
       SUM(CASE WHEN s.STHAR_GCKOD = 'C' THEN s.STHAR_GCMIK * ISNULL(m.OrtBirimMaliyet, 0)
                ELSE -s.STHAR_GCMIK * ISNULL(m.OrtBirimMaliyet, 0) END) AS Maliyet
FROM TBLSTHAR s
LEFT JOIN Maliyet m ON m.STOK_KODU = s.STOK_KODU
LEFT JOIN TBLCASABIT c ON c.CARI_KOD = s.STHAR_CARIKOD
WHERE s.STHAR_FTIRSIP IN ('1','3')
  AND s.STHAR_TARIH >= '20260101'
  AND s.STHAR_TARIH < '20260701'
  AND s.SUBE_KODU = 0
GROUP BY s.STHAR_CARIKOD, c.CARI_ISIM
ORDER BY NetCiro DESC;

Alış hareketi hiç olmayan stokta maliyet sıfır kalır ve marj yüzde yüz görünür. Bu yüzden raporu yayına almadan önce maliyeti sıfır çıkan satırları ayrıca kontrol edin.

3. Ciro lideri ama marjı düşük cariler

Asıl değer burada çıkıyor. Ciroya göre ilk sıralarda olup brüt marjı eşiğin altında kalan müşteriler, ciro büyüttüğü hâlde nakit bırakmayan gruptur. Eşiği 0.15 yerine kendi sektörünüze göre değiştirin.

WITH CariMarj AS (
    SELECT s.STHAR_CARIKOD AS CariKod,
           SUM(CASE WHEN s.STHAR_GCKOD = 'C' THEN s.STHAR_GCMIK * s.STHAR_NF
                    ELSE -s.STHAR_GCMIK * s.STHAR_NF END) AS NetCiro,
           SUM(CASE WHEN s.STHAR_GCKOD = 'C' THEN s.STHAR_GCMIK * (s.STHAR_NF - st.ALIS_FIAT1)
                    ELSE -s.STHAR_GCMIK * (s.STHAR_NF - st.ALIS_FIAT1) END) AS BrutKar
    FROM TBLSTHAR s
    INNER JOIN TBLSTSABIT st ON st.STOK_KODU = s.STOK_KODU
    WHERE s.STHAR_FTIRSIP IN ('1','3')
      AND s.STHAR_TARIH >= '20260101'
      AND s.STHAR_TARIH < '20260701'
      AND s.SUBE_KODU = 0
    GROUP BY s.STHAR_CARIKOD
)
SELECT TOP 20 m.CariKod, c.CARI_ISIM AS CariUnvan,
       CAST(m.NetCiro AS decimal(18,2)) AS NetCiro,
       CAST(m.BrutKar AS decimal(18,2)) AS BrutKar,
       CAST(m.BrutKar / NULLIF(m.NetCiro, 0) * 100 AS decimal(9,2)) AS MarjYuzde
FROM CariMarj m
LEFT JOIN TBLCASABIT c ON c.CARI_KOD = m.CariKod
WHERE m.NetCiro > 0
  AND m.BrutKar / NULLIF(m.NetCiro, 0) < 0.15
ORDER BY m.NetCiro DESC;

4. Marjın aylık seyri: müşteri kârlılığı bozuluyor mu?

Tek dönem marjı, müşterinin sizi yavaşça sıkıştırdığını göstermez. Aynı carinin aylık marj çizgisi düşüyorsa iskonto artıyor ya da satılan ürün karması kayıyor demektir. Tarih işlemini yalnız STHAR_TARIH (datetime) üzerinde yapıyoruz.

SELECT YEAR(s.STHAR_TARIH) AS Yil,
       MONTH(s.STHAR_TARIH) AS Ay,
       SUM(CASE WHEN s.STHAR_GCKOD = 'C' THEN s.STHAR_GCMIK * s.STHAR_NF
                ELSE -s.STHAR_GCMIK * s.STHAR_NF END) AS NetCiro,
       SUM(CASE WHEN s.STHAR_GCKOD = 'C' THEN s.STHAR_GCMIK * st.ALIS_FIAT1
                ELSE -s.STHAR_GCMIK * st.ALIS_FIAT1 END) AS Maliyet,
       CAST(SUM(CASE WHEN s.STHAR_GCKOD = 'C' THEN s.STHAR_GCMIK * (s.STHAR_NF - st.ALIS_FIAT1)
                     ELSE -s.STHAR_GCMIK * (s.STHAR_NF - st.ALIS_FIAT1) END)
            / NULLIF(SUM(CASE WHEN s.STHAR_GCKOD = 'C' THEN s.STHAR_GCMIK * s.STHAR_NF
                              ELSE -s.STHAR_GCMIK * s.STHAR_NF END), 0) * 100
            AS decimal(9,2)) AS MarjYuzde
FROM TBLSTHAR s
INNER JOIN TBLSTSABIT st ON st.STOK_KODU = s.STOK_KODU
WHERE s.STHAR_CARIKOD = '120-001'
  AND s.STHAR_FTIRSIP IN ('1','3')
  AND s.STHAR_TARIH >= '20260101'
  AND s.STHAR_TARIH < '20260701'
  AND s.SUBE_KODU = 0
GROUP BY YEAR(s.STHAR_TARIH), MONTH(s.STHAR_TARIH)
ORDER BY Yil, Ay;

5. Zararına satılan fatura satırları

Cari marjı düşükse sebep genelde birkaç kalemdir. Aşağıdaki sorgu net fiyatı kart alış fiyatının altında kalan satırları doğrudan listeden çıkarır; belge numarası ve stok kodu ile birlikte geldiği için satış temsilcisiyle konuşmak kolaylaşır.

SELECT TOP 50 s.STHAR_TARIH AS Tarih,
       s.FISNO AS BelgeNo,
       s.STHAR_CARIKOD AS CariKod,
       c.CARI_ISIM AS CariUnvan,
       s.STOK_KODU AS StokKodu,
       st.STOK_ADI AS StokAdi,
       s.STHAR_GCMIK AS Miktar,
       s.STHAR_NF AS NetFiyat,
       st.ALIS_FIAT1 AS KartAlisFiyati,
       CAST((s.STHAR_NF - st.ALIS_FIAT1) * s.STHAR_GCMIK AS decimal(18,2)) AS SatirKari
FROM TBLSTHAR s
INNER JOIN TBLSTSABIT st ON st.STOK_KODU = s.STOK_KODU
LEFT JOIN TBLCASABIT c ON c.CARI_KOD = s.STHAR_CARIKOD
WHERE s.STHAR_GCKOD = 'C'
  AND s.STHAR_FTIRSIP IN ('1','3')
  AND s.STHAR_TARIH >= '20260101'
  AND s.STHAR_TARIH < '20260701'
  AND s.SUBE_KODU = 0
  AND s.STHAR_NF < st.ALIS_FIAT1
ORDER BY s.STHAR_TARIH DESC, s.INCKEYNO DESC;

FISNO üzerinden fatura başlığına inmek isterseniz TBLFATUIRS.FATIRS_NO ile birleştirin; ancak FATIRS_NO şubeler arasında tekrar edebildiği için SUBE_KODU ve FTIRSIP ile teyit edin. Stok hareketlerinin genel mantığı için Netsis stok hareketleri yazısına bakabilirsiniz.

6. Plasiyer kırılımı: aynı marj sorunu kimin portföyünde

Cari bazlı tablo iyi bir başlangıç, ama aksiyon plasiyerde alınır. Aynı ölçüleri temsilci bazında toplamak, eğitim mi iskonto yetkisi mi gerektiğini hızla gösterir.

SELECT ISNULL(c.PLASIYER_KODU, 'TANIMSIZ') AS Plasiyer,
       COUNT(DISTINCT s.STHAR_CARIKOD) AS CariSayisi,
       SUM(CASE WHEN s.STHAR_GCKOD = 'C' THEN s.STHAR_GCMIK * s.STHAR_NF
                ELSE -s.STHAR_GCMIK * s.STHAR_NF END) AS NetCiro,
       SUM(CASE WHEN s.STHAR_GCKOD = 'C' THEN s.STHAR_GCMIK * (s.STHAR_NF - st.ALIS_FIAT1)
                ELSE -s.STHAR_GCMIK * (s.STHAR_NF - st.ALIS_FIAT1) END) AS BrutKar
FROM TBLSTHAR s
INNER JOIN TBLSTSABIT st ON st.STOK_KODU = s.STOK_KODU
LEFT JOIN TBLCASABIT c ON c.CARI_KOD = s.STHAR_CARIKOD
WHERE s.STHAR_FTIRSIP IN ('1','3')
  AND s.STHAR_TARIH >= '20260101'
  AND s.STHAR_TARIH < '20260701'
  AND s.SUBE_KODU = 0
GROUP BY c.PLASIYER_KODU
ORDER BY NetCiro DESC;

Sık yapılan hatalar

  • STHAR_FTIRSIP filtresini koymamak: alış faturası, transfer ve irsaliye satırları satış cirosuna karışır, marj olduğundan yüksek çıkar.
  • STHAR_GCKOD yönünü yok saymak: iade edilen mal stok girişidir; yön ayrımı yapılmazsa hem ciro hem maliyet şişer.
  • SUBE_KODU ve ISLETME_KODU filtresini atlamak: çok şubeli kurulumda iki şubenin satışı tek cariye yazılır, marj ortalaması bozulur.
  • ALIS_FIAT1 ile dönem maliyeti sanmak: kart fiyatı günceldir, geçmiş ayların marjını yanlış gösterir; dönemsel analizde alış hareketlerinden ortalama alın.
  • KDV dahil tutarla marj hesaplamak: STHAR_NF net fiyattır, KDV hariçtir; KDV dahil satış fiyatıyla kıyaslarsanız marj olduğundan düşük çıkar.
  • Tarih koşulunu kod alanlarına yazmak: SUBE_KODU, DEPO_KODU gibi sayısal alanları tarihle karşılaştırmak örtük dönüşüm hatası (8115 taşması) üretir; tarih işlemi yalnız STHAR_TARIH üzerinde yapılmalı.
  • Sipariş kalemlerini TBLSTHAR içinde aramak: müşteri siparişi kalemleri TBLSIPATRA tablosundadır, burada bulamazsınız.
  • STOK_KODU eşleşmesini INNER JOIN yapıp kartı silinmiş stokları tamamen düşürmek: satır kaybolur, ciro eksik toplanır; LEFT JOIN ile deneyip farkı kontrol edin.

Sık sorulanlar

Marjı hangi fiyattan hesaplamalıyım, STHAR_NF mi STHAR_BF mi? STHAR_NF iskonto ve KDV sonrası net birim fiyattır, gerçekleşen satışı yansıtır. STHAR_BF liste/brüt fiyattır; marj analizinde STHAR_NF kullanın, aksi hâlde verilen iskontoyu kâr gibi sayarsınız.

Aynı cari hem alıcı hem satıcıysa ne olur? Ciro tarafında yalnız STHAR_FTIRSIP IN ('1','3') ve STHAR_GCKOD = 'C' satırları toplandığı için alım yaptığınız satırlar rapora girmez. Cariyi CARI_TIP ile ayırmak istiyorsanız TBLCASABIT tarafına filtre ekleyin.

Maliyet sıfır çıkan satırlar neden var? O stok için seçilen dönemde ve şubede alış hareketi yoktur ya da ALIS_FIAT1 boştur. Bu satırları marj ortalamasına katmadan önce stok kartını kontrol edin; aksi hâlde marjınız olduğundan yüksek görünür.

Rapor çok yavaş çalışıyor, ne yapmalıyım? Dönem aralığını daraltın, STHAR_TARIH ve STHAR_FTIRSIP filtrelerini her sorguda koruyun; tüm yılları tarayan bir kârlılık raporu hem yavaştır hem de eski maliyetlerle yanıltıcıdır.


Cari kârlılık raporu, ciro listesinin tek başına yetmediğini gösteren en net örnektir: büyük ciro her zaman büyük kâr değildir. Altı sorgu iyi bir başlangıç, ama her firmanın marj eşiği, maliyet yöntemi ve dönem tanımı farklı. Erp Asistanı'na ücretsiz üye olun, ihtiyacınızı tek cümleyle yazın; Netsis şemanıza uygun SQL'i saniyeler içinde alın.

Ücretsiz üye olun, kârlılık sorgunuzu doğal dille alın →

Bu yazıyı paylaş
Netsis raporlama

Bu raporu SQL yazmadan, Türkçe sorarak alın

Türkçe sorunuzu yazın, şemanıza uygun çalışan SQL'i ya da hazır uygulamanızı saniyeler içinde alın.