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ı
Editör ekibi
10 dk okuma
İçindekiler
"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
Accountkolonundan toplamak: kontrol hesabı (ör. 120 alıcılar) bütün müşterilerin ortak hesabıdır. Tek bir carinin bakiyesiShortName = CardCodeile süzülür. - Yaşlandırmayı fatura tarihinden hesaplamak: gecikme vadeden sayılır;
DocDatedeğilDocDueDate(yevmiyedeDueDate) kullanın. CANCELEDfiltresini 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.
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.