Erp Asistanı Erp Asistanı
SAP SQL

SAP Business One Cari Bakiye ve Yaşlandırma SQL: JDT1 ile Doğru Hesap

SAP Business One'da cari bakiye, açık faturalar ve 30/60/90 gün yaşlandırma hangi SQL ile alınır? OCRD.Balance tuzağı, JDT1 açık kalemleri, yürüyen bakiyeli cari ekstre ve tahsilat gecikmesi. Test edilmiş sorgular.

Erp Asistanı Erp Asistanı Editör ekibi 10 dk okuma
SAP Business One Cari Bakiye ve Yaşlandırma SQL: JDT1 ile Doğru Hesap

"Hangi müşteri bize ne kadar borçlu, bu borcun ne kadarı vadesini geçti?" Finans ekibinin her hafta sorduğu bu soru SAP Business One'da üç farklı yerden cevaplanabilir: cari kartındaki bakiye alanı, açık faturalar ve yevmiye satırları. Üçü her zaman aynı sonucu vermez. Bu rehberde cari bakiyeyi yevmiyeden (JDT1) doğru hesaplamayı, açık faturaları listelemeyi, 30/60/90 gün yaşlandırma raporunu kurmayı ve yürüyen bakiyeli cari ekstreyi çıkarmayı anlatıyoruz. Sorgular SAP'nin resmi Türkiye demo şirketinde (SAP Business One 10.0, SQL Server) çalıştırılarak test edildi.

Cari bakiye nerede durur?

Kaynak Ne verir Ne zaman güvenilir
OCRD.Balance Kart üzerinde tutulan hazır bakiye Hızlı bakış için; işaretini kendi kurulumunuzda doğrulayın
OINV (DocTotal - PaidToDate, DocStatus = 'O') Açık fatura bazında alacak Fatura yaşlandırması için; eşleştirilmemiş tahsilat ve iadeleri görmez
JDT1 (Debit - Credit, BalDueDeb - BalDueCred) Yevmiyeden bakiye ve açık kalemler Muhasebeyle birebir tutan tek kaynak; rapor buradan kurulur

SAP Business One'da her fatura, tahsilat ve iade bir yevmiye kaydı üretir. Cari hesabı ilgilendiren yevmiye satırında ShortName kolonu cari kodunu (CardCode) taşır, Account kolonu ise carinin bağlı olduğu kontrol hesabını (Türkiye kurulumlarında genellikle 120 alıcılar altındaki bir hesap). Bu yüzden carinin bakiyesi, ShortName = CardCode olan satırların borç-alacak farkıdır.

1. Yevmiyeden cari bakiye listesi

-- Müşteri bakiyeleri: pozitif = müşteri bize borçlu
SELECT c.CardCode               AS CariKod,
       c.CardName               AS CariAd,
       SUM(j.Debit)             AS ToplamBorc,
       SUM(j.Credit)            AS ToplamAlacak,
       SUM(j.Debit - j.Credit)  AS Bakiye
FROM JDT1 j
JOIN OCRD c ON c.CardCode = j.ShortName
WHERE c.CardType = 'C'
GROUP BY c.CardCode, c.CardName
HAVING SUM(j.Debit - j.Credit) <> 0
ORDER BY Bakiye DESC;

Tedarikçi borçlarınız için CardType = 'S' yazın; tedarikçide alacak bakiyesi beklenir, bu yüzden SUM(j.Credit - j.Debit) daha okunur sonuç verir. Tutarlar yerel para birimindedir; dövizli cariler için döviz bakiyesi FCDebit - FCCredit ile alınır.

2. Kart bakiyesini yevmiyeyle karşılaştırın

OCRD.Balance pratik bir alan ama işaretine körü körüne güvenmeyin. Ölçtüğümüz demo şirkette 12 müşterinin 12'sinde kart bakiyesi yevmiyenin ters işaretindeydi (yevmiye +77.661,70 iken kartta -77.661,70). Kendi kurulumunuzda iki değeri yan yana görmek bir sorgu sürer:

SELECT c.CardCode                    AS CariKod,
       c.CardName                    AS CariAd,
       c.Balance                     AS KarttakiBakiye,
       ISNULL(y.YevmiyeBakiyesi, 0)  AS YevmiyeBakiyesi
FROM OCRD c
LEFT JOIN (
    SELECT ShortName, SUM(Debit - Credit) AS YevmiyeBakiyesi
    FROM JDT1
    GROUP BY ShortName
) y ON y.ShortName = c.CardCode
WHERE c.CardType = 'C'
ORDER BY c.CardCode;

İki sütun mutlak değerce eşitse kart alanı güncel demektir; işaret farkı varsa raporda yevmiye sütununu kullanın.

3. Açık (ödenmemiş) faturalar

Fatura başlığında PaidToDate o faturaya o ana kadar eşleştirilmiş tahsilat toplamıdır. Kalan borç DocTotal - PaidToDate, açık fatura DocStatus = 'O' ile bulunur.

SELECT f.CardCode                  AS CariKod,
       c.CardName                  AS CariAd,
       f.DocNum                    AS FaturaNo,
       f.DocDate                   AS FaturaTarihi,
       f.DocDueDate                AS Vade,
       f.DocTotal                  AS FaturaTutari,
       f.PaidToDate                AS Odenen,
       f.DocTotal - f.PaidToDate   AS Kalan
FROM OINV f
JOIN OCRD c ON c.CardCode = f.CardCode
WHERE f.CANCELED = 'N'
  AND f.DocStatus = 'O'
ORDER BY f.CardCode, f.DocDueDate;

Taksitli faturalarda (vadesi birden çok parçaya bölünmüş) vade tarihleri INV6 tablosundadır; başlıktaki DocDueDate yalnız son vadeyi gösterir.

4. 30/60/90 gün yaşlandırma (fatura bazlı)

Yaşlandırma, açık tutarı vadesinden bu yana geçen güne göre kovalara dağıtır. Gün hesabı faturanın kesildiği tarihten değil vade tarihinden yapılır.

DECLARE @Bugun date = CAST(GETDATE() AS date);

SELECT f.CardCode AS CariKod,
       c.CardName AS CariAd,
       SUM(CASE WHEN f.DocDueDate >= @Bugun
                THEN f.DocTotal - f.PaidToDate ELSE 0 END) AS VadesiGelmemis,
       SUM(CASE WHEN DATEDIFF(DAY, f.DocDueDate, @Bugun) BETWEEN 1 AND 30
                THEN f.DocTotal - f.PaidToDate ELSE 0 END) AS Gecikme_1_30,
       SUM(CASE WHEN DATEDIFF(DAY, f.DocDueDate, @Bugun) BETWEEN 31 AND 60
                THEN f.DocTotal - f.PaidToDate ELSE 0 END) AS Gecikme_31_60,
       SUM(CASE WHEN DATEDIFF(DAY, f.DocDueDate, @Bugun) BETWEEN 61 AND 90
                THEN f.DocTotal - f.PaidToDate ELSE 0 END) AS Gecikme_61_90,
       SUM(CASE WHEN DATEDIFF(DAY, f.DocDueDate, @Bugun) > 90
                THEN f.DocTotal - f.PaidToDate ELSE 0 END) AS Gecikme_90_Ustu,
       SUM(f.DocTotal - f.PaidToDate)                       AS ToplamAcik
FROM OINV f
JOIN OCRD c ON c.CardCode = f.CardCode
WHERE f.CANCELED = 'N'
  AND f.DocStatus = 'O'
GROUP BY f.CardCode, c.CardName
ORDER BY ToplamAcik DESC;

Bu rapor yalnız faturaları görür. Faturaya eşleştirilmemiş bir tahsilat (müşteri ödedi ama muhasebe henüz faturayla kapatmadı) ya da açık bir alacak dekontu müşterinin borcunu azaltır, fatura bazlı raporda ise görünmez. Muhasebeyle birebir tutan yaşlandırma için bir sonraki sorguyu kullanın.

5. Açık kalem bazlı yaşlandırma (yevmiyeden)

Yevmiye satırındaki BalDueDeb ve BalDueCred kolonları o satırın henüz eşleştirilmemiş (kapanmamış) kısmını tutar. Açık faturalar borç tarafında, eşleştirilmemiş tahsilat ve alacak dekontları alacak tarafında kalır; ikisinin farkı carinin net açık bakiyesidir. Vade, satırın DueDate kolonundadır.

DECLARE @Bugun date = CAST(GETDATE() AS date);

SELECT j.ShortName AS CariKod,
       c.CardName  AS CariAd,
       SUM(CASE WHEN j.DueDate >= @Bugun
                THEN j.BalDueDeb - j.BalDueCred ELSE 0 END) AS VadesiGelmemis,
       SUM(CASE WHEN DATEDIFF(DAY, j.DueDate, @Bugun) BETWEEN 1 AND 30
                THEN j.BalDueDeb - j.BalDueCred ELSE 0 END) AS Gecikme_1_30,
       SUM(CASE WHEN DATEDIFF(DAY, j.DueDate, @Bugun) BETWEEN 31 AND 60
                THEN j.BalDueDeb - j.BalDueCred ELSE 0 END) AS Gecikme_31_60,
       SUM(CASE WHEN DATEDIFF(DAY, j.DueDate, @Bugun) BETWEEN 61 AND 90
                THEN j.BalDueDeb - j.BalDueCred ELSE 0 END) AS Gecikme_61_90,
       SUM(CASE WHEN DATEDIFF(DAY, j.DueDate, @Bugun) > 90
                THEN j.BalDueDeb - j.BalDueCred ELSE 0 END) AS Gecikme_90_Ustu,
       SUM(j.BalDueDeb - j.BalDueCred)                       AS NetAcikBakiye
FROM JDT1 j
JOIN OCRD c ON c.CardCode = j.ShortName
WHERE c.CardType = 'C'
  AND (j.BalDueDeb <> 0 OR j.BalDueCred <> 0)
GROUP BY j.ShortName, c.CardName
ORDER BY NetAcikBakiye DESC;

Demo şirkette iki raporun toplamı kuruşu kuruşuna aynı çıktı (1.920.252,94), çünkü demo veride eşleştirilmemiş tahsilat yok. Gerçek bir şirkette fark çıkarsa farkın kaynağı neredeyse her zaman faturayla eşleştirilmemiş tahsilatlardır; bunları muhasebede kapatmak raporu da düzeltir.

6. Yürüyen bakiyeli cari ekstre

Ekstre, seçilen dönemden önceki bakiyeyi (devir) açılış satırı olarak alır ve her hareketten sonraki bakiyeyi gösterir. SQL Server'ın pencere fonksiyonu (SUM() OVER) bunu tek sorguda yapar:

DECLARE @Cari nvarchar(15) = N'C20000';   -- cari kodunuz
DECLARE @Baslangic date = '20260101';

DECLARE @Devir numeric(19, 6) = (
    SELECT ISNULL(SUM(Debit - Credit), 0)
    FROM JDT1
    WHERE ShortName = @Cari AND RefDate < @Baslangic
);

SELECT j.RefDate                                  AS Tarih,
       CASE j.TransType
            WHEN '13' THEN N'Satış faturası'
            WHEN '14' THEN N'Alacak dekontu'
            WHEN '24' THEN N'Tahsilat'
            WHEN '46' THEN N'Tediye'
            WHEN '30' THEN N'Yevmiye kaydı'
            ELSE j.TransType
       END                                        AS IslemTuru,
       j.BaseRef                                  AS BelgeNo,
       j.DueDate                                  AS Vade,
       j.Debit                                    AS Borc,
       j.Credit                                   AS Alacak,
       @Devir + SUM(j.Debit - j.Credit) OVER (
           ORDER BY j.RefDate, j.TransId, j.Line_ID
           ROWS UNBOUNDED PRECEDING)              AS Bakiye
FROM JDT1 j
WHERE j.ShortName = @Cari
  AND j.RefDate >= @Baslangic
ORDER BY j.RefDate, j.TransId, j.Line_ID;

TransType kolonu metin tipindedir, bu yüzden kodlar tırnak içinde yazılır ('13'). BaseRef kaynak belgenin kullanıcıya görünen numarasını taşır. Ekstrenin ilk satırına devir bakiyesini ayrıca göstermek isterseniz @Devir değerini raporun başlığına yazdırmanız yeterli.

7. Tahsilat hangi faturayı kapattı, kaç gün gecikti?

Tahsilat başlığı ORCT, tahsilatın kapattığı faturalar RCT2 tablosundadır. Burada SAP'nin kafa karıştıran bir adlandırması var: RCT2.DocNum tahsilatın DocEntry değerini, RCT2.DocEntry ise kapatılan faturanın DocEntry değerini tutar.

SELECT r.DocNum                                AS TahsilatNo,
       r.DocDate                               AS TahsilatTarihi,
       r.CardCode                              AS CariKod,
       f.DocNum                                AS FaturaNo,
       f.DocDueDate                            AS Vade,
       t.SumApplied                            AS KapatilanTutar,
       DATEDIFF(DAY, f.DocDueDate, r.DocDate)  AS GecikmeGunu
FROM ORCT r
JOIN RCT2 t ON t.DocNum = r.DocEntry
JOIN OINV f ON f.DocEntry = t.DocEntry
WHERE r.Canceled = 'N'
  AND t.InvType = '13'          -- 13 = satış faturası
  AND r.DocDate >= DATEADD(MONTH, -6, CAST(GETDATE() AS date))
ORDER BY r.DocDate DESC;

Aynı sorguyu CardCode ile gruplayıp AVG(DATEDIFF(...)) alırsanız müşteri bazında ortalama ödeme gecikmesini, yani tahsilat disiplinini ölçen bir rapor elde edersiniz.

Sık yapılan hatalar

  • Bakiyeyi Account kolonundan toplamak: kontrol hesabı (ör. 120 alıcılar) bütün müşterilerin ortak hesabıdır. Tek bir carinin bakiyesi ShortName = CardCode ile süzülür.
  • Yaşlandırmayı fatura tarihinden hesaplamak: gecikme vadeden sayılır; DocDate değil DocDueDate (yevmiyede DueDate) kullanın.
  • CANCELED filtresini unutmak: iptal edilmiş fatura açık görünmez ama ciro ve hareket raporlarında iki kez sayılabilir. Tahsilatta kolon adı Canceled'dır.
  • Fatura bazlı raporu muhasebe bakiyesi sanmak: eşleştirilmemiş tahsilatlar fatura raporunda görünmez; müşteriye "borcunuz" diye gönderilecek rakam yevmiyeden alınmalıdır.
  • Türkçe cari adı ararken N önekini unutmak: CardName LIKE '%Şahin%' boş dönebilir; CardName LIKE N'%Şahin%' yazın.

Sık sorulanlar

SAP Business One'da cari bakiyesi hangi tabloda? Kart üzerindeki hazır bakiye OCRD.Balance kolonundadır, ama muhasebeyle birebir tutan bakiye yevmiye satırlarından (JDT1) hesaplanır: ShortName = CardCode olan satırlarda SUM(Debit - Credit).

JDT1'deki ShortName ile Account farkı nedir? Account satırın işlendiği muhasebe hesabıdır; cari satırlarında bu, carinin kontrol hesabıdır (ör. 120 alıcılar). ShortName ise cari satırlarında cari kodunu, diğer satırlarda hesap kodunu taşır. Cari bazında rapor ShortName ile kurulur.

Açık fatura tutarı nasıl hesaplanır? DocTotal - PaidToDate. PaidToDate, faturaya eşleştirilmiş tahsilatların toplamıdır. Faturanın tamamen kapanıp kapanmadığını DocStatus kolonu söyler: O açık, C kapalı.

Yaşlandırma raporum SAP'nin kendi yaşlandırma ekranıyla neden tutmuyor? En sık sebep, fatura bazlı raporun eşleştirilmemiş tahsilatları ve açık alacak dekontlarını görmemesidir. Yevmiyedeki açık kalemlerden (BalDueDeb - BalDueCred) kurulan yaşlandırma bunları da hesaba katar. Ayrıca SAP ekranının vade tarihine mi belge tarihine mi göre yaşlandırdığını kontrol edin.


Her ay aynı yaşlandırma raporunu elle hazırlamak yerine Erp Asistanı'na "vadesi 60 günü geçen müşteri borçlarını getir" yazın; sistem SAP Business One şemanıza uygun SQL'i üretir, isterseniz sonucu tablo ve grafik olarak gösterir. Tablolara genel bakış için SAP Business One tablo yapısı rehberi, hazır sorgular için SAP Business One hazır SQL sorguları yazılarına göz atın.

Ücretsiz üye olun, SAP sorgunuzu doğal dille üretin →

Bu yazıyı paylaş
Konuşarak raporlayın

SAP Business One'da SQL ve raporu konuşarak 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.