ERP Asistanı Dal Net
SAP SQL

SAP B1 Stok Hareketleri SQL: OINM ile Stok Föyü ve Devir

OINM ile SAP Business One stok föyü: TransType kodları, depo bazında yürüyen bakiye, dönem başı devir ve dönem giriş çıkış özeti SQL sorguları.

Erp Asistanı Erp Asistanı Editör ekibi 10 dk okuma
SAP B1 Stok Hareketleri SQL: OINM ile Stok Föyü ve Devir

SAP Business One'da stok hareketlerinin tek adresi OINM'dir (Warehouse Journal). Stok kartındaki OnHand yalnız bugünkü miktarı verir; geçen ay sonunda depoda kaç adet vardı, dönem içinde ne girdi ne çıktı, bu hareket hangi belgeden doğdu sorularının cevabı OINM satırlarındadır. Bu yazıda OINM'i stok föyü olarak okumanın kalıbını, TransType kodlarını, depo bazında yürüyen bakiyeyi ve dönem başı devir hesabını SQL ile kuruyoruz. Sorguların tamamı yalnız okuma yapar; veritabanına yazan tek satır yoktur. Tablo adlarının mantığını bilmiyorsanız önce SAP Business One tablo yapısı rehberine bakın.

OINM'i tanımak: altı kolon yeter

OINM her stok girişi ve çıkışı için bir satır tutar. Miktar iki kolona bölünmüştür: satırın birinde InQty, diğerinde OutQty doludur, ikisi birden asla dolu olmaz. Net miktar her zaman SUM(InQty - OutQty) ile bulunur.

Kolon Anlam
ItemCode stok kodu (OITM.ItemCode)
Warehouse depo kodu, metindir: '01', 1 değil
DocDate hareket tarihi (datetime)
InQty / OutQty giren / çıkan miktar, stok birimiyle
TransType / BASE_REF hareketi doğuran belge türü / o belgenin numarası (metin)
TransNum hareket sıra numarası; aynı gün içindeki sıralama anahtarı

SAP Business One 10.0'da OINM bir uyumluluk görünümüdür, asıl veri OIVL ve OILM tarafında durur. Okumak için OINM kullanın; bu görünüm üzerinden yazma yapılmaz. Yoğun sorguda tarih ve ürün filtresini en başa koyun.

TransType: hareket hangi belgeden doğdu

Stok föyünü okurken en çok karıştırılan nokta budur: hareketi yaratan belge türü TransType, belgenin numarası BASE_REF içindedir. BASE_REF metin kolonudur, JOIN'de kullanılmaz; eşleştirme gerekiyorsa belge tarafında DocEntry kullanın.

TransType Hareket Yön
15 Satış irsaliyesi Çıkış
16 Satış iade irsaliyesi Giriş
13 / 14 Satış faturası / iade faturası Yalnız irsaliyesiz kesildiyse
20 Mal girişi (satınalma) Giriş
21 Satınalma iadesi Çıkış
18 / 19 Alış faturası / iade Yalnız mal girişsiz kesildiyse
59 / 60 Stok girişi / stok çıkışı Giriş / Çıkış
67 Depo transferi Çıkış + giriş (iki satır)
202 Üretim emri Emre göre
162 Stok değerleme Miktar değişmez
310000001 Stok açılış bakiyesi Giriş

Satış faturası irsaliyeden kopyalandıysa stok irsaliyede düşer, fatura stok hareketi yazmaz. Bu yüzden satış föylerinde 13 yerine 15 görürsünüz; bu bir eksiklik değil, doğru davranıştır. Ciro ve satılan miktar raporu için OINM değil INV1 / RIN1 kullanılır; OINM stok bakışıdır. Hazır ciro sorguları için SAP Business One hazır SQL sorguları yazısına bakabilirsiniz.

Tek ürünün stok föyü: yürüyen bakiye

Depo bazında yürüyen miktarı pencere fonksiyonu ile kuruyoruz. PARTITION BY Warehouse deposuz toplam ile depo bazlı bakiyeyi ayırır; ROWS UNBOUNDED PRECEDING çalışan toplamı verir.

SELECT m.DocDate, m.Warehouse, m.TransType, m.BASE_REF AS BelgeNo,
       m.CardCode, m.InQty AS Giren, m.OutQty AS Cikan,
       SUM(m.InQty - m.OutQty) OVER (PARTITION BY m.Warehouse
                                     ORDER BY m.DocDate, m.TransNum
                                     ROWS UNBOUNDED PRECEDING) AS Bakiye
FROM OINM m
WHERE m.ItemCode = N'P10001'
ORDER BY m.Warehouse, m.DocDate, m.TransNum;

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

Sıralamada DocDate tek başına yetmez: aynı gün birden fazla hareket varsa bakiye satırlar arasında zıplar. TransNum ikinci sıralama anahtarıdır, tek başına kullanıldığında ise depo geçişlerinde bakiye karışır.

Dönemsel giriş çıkış özeti

Dönem raporunda tarih aralığını yarı açık kurun: başlangıç dahil, bitiş hariç. Böylece ay sonu ile sonraki ayın ilk günü çakışmaz.

SELECT m.ItemCode, i.ItemName, m.Warehouse, w.WhsName,
       SUM(m.InQty) AS Giren, SUM(m.OutQty) AS Cikan,
       SUM(m.InQty - m.OutQty) AS Net
FROM OINM m
JOIN OITM i ON i.ItemCode = m.ItemCode
LEFT JOIN OWHS w ON w.WhsCode = m.Warehouse
WHERE m.DocDate >= '2025-01-01' AND m.DocDate < '2026-01-01'
GROUP BY m.ItemCode, i.ItemName, m.Warehouse, w.WhsName
HAVING SUM(m.InQty) <> 0 OR SUM(m.OutQty) <> 0
ORDER BY m.ItemCode, m.Warehouse;

HAVING satırı yalnız değerleme (162) gibi miktarsız hareketlerden doğan boş satırları eler. Depo adı OWHS üzerinden gelir; Warehouse kolonunda depo adı değil kod vardır.

Dönem başı devir ayrı hesaplanır

En sık yapılan hata, dönem raporuna tarih filtresi koyup bakiye sanmaktır. Filtre hareketleri kısar, geçmişi silmez: devir, başlangıç tarihinden önceki tüm hareketlerin toplamıdır. Aşağıdaki tek sorgu devir, dönem ve dönem sonunu birlikte verir.

SELECT d.ItemCode, d.Warehouse,
       SUM(CASE WHEN d.DocDate < '2025-01-01' THEN d.InQty - d.OutQty ELSE 0 END) AS Devir,
       SUM(CASE WHEN d.DocDate >= '2025-01-01' AND d.DocDate < '2026-01-01' THEN d.InQty ELSE 0 END) AS DonemGiris,
       SUM(CASE WHEN d.DocDate >= '2025-01-01' AND d.DocDate < '2026-01-01' THEN d.OutQty ELSE 0 END) AS DonemCikis,
       SUM(CASE WHEN d.DocDate < '2026-01-01' THEN d.InQty - d.OutQty ELSE 0 END) AS DonemSonu
FROM OINM d
GROUP BY d.ItemCode, d.Warehouse
HAVING SUM(CASE WHEN d.DocDate < '2026-01-01' THEN d.InQty - d.OutQty ELSE 0 END) <> 0
ORDER BY d.ItemCode, d.Warehouse;

Kontrolü kolaydır: Devir + DonemGiris - DonemCikis = DonemSonu. Tutmuyorsa tarih aralığına bir sınır eksik yazılmıştır.

Hareket türü kırılımı

Föyün neden arttığını ya da azaldığını görmek için hareketi doğuran belge türüne göre gruplayın.

SELECT m.TransType,
       CASE m.TransType
            WHEN 15 THEN N'Satış irsaliyesi'
            WHEN 16 THEN N'Satış iade irsaliyesi'
            WHEN 20 THEN N'Mal girişi'
            WHEN 21 THEN N'Satınalma iadesi'
            WHEN 59 THEN N'Stok girişi'
            WHEN 60 THEN N'Stok çıkışı'
            WHEN 67 THEN N'Depo transferi'
            ELSE N'Diğer'
       END AS Hareket,
       COUNT(*) AS SatirSayisi,
       SUM(m.InQty) AS Giren, SUM(m.OutQty) AS Cikan
FROM OINM m
WHERE m.DocDate >= '2025-01-01' AND m.DocDate < '2026-01-01'
GROUP BY m.TransType
ORDER BY SatirSayisi DESC;

Türkçe etiketleri N'...' ile yazıyoruz: veritabanının collation'ı Türkçe olmadığında öneksiz literal ş, ğ, İ karakterlerini sessizce bozar.

Belirli bir tarihteki stok

OITM.OnHand ve depo kırılımı yalnız bugünü tutar. Geçmişe dönük miktar için OINM'i kesme tarihine kadar toplamak gerekir.

SELECT m.ItemCode, m.Warehouse, SUM(m.InQty - m.OutQty) AS Miktar
FROM OINM m
WHERE m.DocDate < DATEADD(DAY, 1, CAST(GETDATE() AS date))
GROUP BY m.ItemCode, m.Warehouse
HAVING SUM(m.InQty - m.OutQty) <> 0
ORDER BY m.ItemCode, m.Warehouse;

Kesme tarihini geriye almak için DATEADD satırını '2025-09-30' gibi sabit bir tarihle değiştirin. HAVING sıfır bakiye satırlarını listeden çıkarır.

Föy ile kart stoğu mutabakatı

Föy toplamı ile stok kartındaki miktar tutmuyorsa sorun genelde dönem filtresi ya da açılış bakiyesidir. Aşağıdaki sorgu farkı olan kalemleri doğrudan listeler.

SELECT i.ItemCode, i.ItemName, i.OnHand AS KartStok,
       ISNULL(h.HareketStok, 0) AS FoyStok,
       i.OnHand - ISNULL(h.HareketStok, 0) AS Fark
FROM OITM i
LEFT JOIN (SELECT m.ItemCode, SUM(m.InQty - m.OutQty) AS HareketStok
           FROM OINM m
           GROUP BY m.ItemCode) h ON h.ItemCode = i.ItemCode
WHERE i.InvntItem = 'Y'
  AND i.OnHand <> ISNULL(h.HareketStok, 0)
ORDER BY Fark DESC;

Fark tek bir üründe ve sürekli aynı miktardaysa açılış bakiyesi (310000001) ya da sayım düzeltmesi (59/60) gözden kaçmıştır. Fark çok üründe ve gün gün büyüyorsa entegrasyon tarafına bakın: Stok senkronizasyonu neden bozulur yazısı bu üç senaryoyu örneklerle anlatır.

Depo transferi kontrolü

Depo transferi (67) her zaman iki satır üretir: çıkan depoda OutQty, giren depoda InQty. Şirket toplamında net etkisi sıfırdır, depo bazında değil. Aşağıdaki sorgu belge içinde girişi çıkışına eşit olmayan transferleri gösterir; sağlıklı bir veritabanında boş döner.

SELECT m.DocDate, m.BASE_REF AS TransferNo, m.ItemCode,
       SUM(m.InQty) AS TransferGiren, SUM(m.OutQty) AS TransferCikan
FROM OINM m
WHERE m.TransType = 67
  AND m.DocDate >= '2025-01-01'
GROUP BY m.DocDate, m.BASE_REF, m.ItemCode
HAVING SUM(m.InQty) <> SUM(m.OutQty)
ORDER BY m.DocDate DESC;

Sık yapılan hatalar

  • OINM'i ciro raporu sanmak: satılan miktar INV1 / RIN1 tarafındadır, OINM stok bakışıdır.
  • Dönem raporunda devir satırını atlamak: filtre hareketleri kısar, geçmiş bakiyeyi silmez. Devir her zaman ayrı toplanır.
  • Yürüyen bakiyeyi yalnız DocDate ile sıralamak: aynı gün içinde bakiye zıplar, TransNum şart.
  • Faturada (13) stok hareketi aramak: irsaliyeden kopyalanan fatura stok yazmaz, hareket 15'te durur.
  • Depo kodunu sayı sanmak: Warehouse metindir, '01' ile 1 aynı şey değildir.
  • Geçmiş tarihli stoğu OITW.OnHand üzerinden okumak: o kolonlar yalnız bugünü tutar.
  • BASE_REF ile belgeye JOIN kurmak: kolon metindir, eşleştirme DocEntry üzerinden yapılır.

Sık sorulanlar

OINM toplamı neden OITW.OnHand ile tutmuyor? OITW bugünkü miktarı tutar, sizin sorgunuz ise tarih filtresiyle geçmişi topluyor olabilir. Tarih filtresini kaldırıp mutabakat sorgusunu çalıştırın; fark hala varsa açılış bakiyesi veya sayım düzeltmesi eksik okunuyordur.

Stok föyünde neden satış faturası (13) hiç yok? Fatura irsaliyeden kopyalandığında stok hareketi irsaliyede oluşur ve TransType = 15 yazar. Yalnız irsaliyesiz kesilen faturalarda fatura türü stok hareketi üretir.

Aynı gün içinde yürüyen bakiye neden düzensiz? Sıralama anahtarınız eksik. ORDER BY DocDate, TransNum kullanın; TransNum hareketin oluşma sırasını taşır.

Bu sorgular SAP HANA'da çalışır mı? Mantık aynıdır ama sözdizimi farklıdır: tarih fonksiyonları ve tablo adlarının çift tırnakla yazımı değişir. Buradaki T-SQL sorguları SQL Server sürümü içindir.


Stok föyünü her ay elle uyarlamak yerine sorunuzu Türkçe yazabilirsiniz: Erp Asistanı SAP Business One şemanıza uygun, doğrulanmış SQL'i üretir. Nasıl çalıştığını SQL Üretme rehberinde görebilirsiniz.

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

Bu yazıyı paylaş
SAP Business One 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.