Stok hatası neye mal olur?
E-ticarette stok sayısı yalnızca depodaki adet değildir; sitenizde, pazaryerlerinde ve hazırlanmakta olan siparişlerde aynı anda verilen bir sözdür. Stok yanlış yönetildiğinde kayıp üç biçimde ortaya çıkar:- Fazla satış (overselling): Elde olmayan ürünü satmak. Sipariş iptal edilir, müşteri bir daha gelmeyebilir; pazaryerlerinde satıcı kaynaklı iptaller satıcı performans ölçütlerine de yansır. Türkiye'de işin hukuki bir boyutu da vardır: Mesafeli Sözleşmeler Yönetmeliği'nin 16. maddesine göre malın stokta bulunmaması, edimin yerine getirilmesinin imkânsızlaşması sayılmaz. Bu yüzden "stokta yok" gerekçesiyle yapılan iptal hukuki risk de taşır.
- Stoksuz kalma (stockout): Ürünün en çok sattığı anda tükenmesi. Reklam bütçesi boşa gider; ürünün aramada ve pazaryeri listelerinde kazandığı görünürlük zayıflayabilir.
- Ölü stok (dead stock): Satılmayan ürüne bağlanan sermaye, depo maliyeti ve sonunda indirimle eritme zorunluluğu.
Dört sayı: eldeki, rezerve, satılabilir, yoldaki
Tek bir "stok" sütunu sorunların çoğunun kaynağıdır. En azından şu dört kavramı ayırın:| Kavram | Tanım | Neyle değişir |
|---|---|---|
| Eldeki stok (on hand) | Depoda fiziksel olarak duran adet | Mal kabul, sevkiyat, iade, sayım düzeltmesi |
| Rezerve (reserved) | Siparişi alınmış ama henüz depodan çıkmamış adet | Sipariş, iptal, rezervasyon süresinin dolması, sevkiyat |
| Satılabilir stok (available to sell) | Eldeki − rezerve − satış tamponu | Hesaplanır, elle girilmez |
| Yoldaki stok (incoming) | Tedarikçiye sipariş verilmiş, henüz gelmemiş adet | Satın alma siparişi, mal kabul |
Veri modeli: sayaç değil, hareket kaydı
"Stok = 17" diye tutulan bir sayaç yanlış çıktığında nedenini kimse bulamaz. Bunun yerine her değişikliği bir hareket satırı olarak yazın; eldeki stok, hareketlerin toplamıdır. Örnekler MySQL söz dizimiyle yazılmıştır:
SQL:
CREATE TABLE stock_movements (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
sku VARCHAR(64) NOT NULL,
warehouse_id INT NOT NULL,
qty INT NOT NULL, -- giriş artı, çıkış eksi
reason VARCHAR(32) NOT NULL, -- receipt, shipment, return_restock, adjustment, transfer
ref VARCHAR(64), -- sipariş, satın alma ya da sayım numarası
created_by VARCHAR(64) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_sku_wh (sku, warehouse_id)
);
-- Eldeki stok = hareketlerin toplamı
SELECT sku, warehouse_id, SUM(qty) AS on_hand
FROM stock_movements
GROUP BY sku, warehouse_id;
Ödeme akışında rezervasyon ve yarış koşulu
Son ürünü iki müşteri aynı saniyede almaya çalıştığında "önce stoğu oku, sonra düş" yaklaşımı ikisine de satış yapar. Kontrolü ve ayırmayı tek bir koşullu UPDATE sorgusunda birleştirin:
SQL:
-- Yeterli satılabilir stok varsa rezerve et: tek sorgu, yarış koşulu yok
UPDATE stock_levels
SET reserved = reserved + :qty
WHERE sku = :sku
AND warehouse_id = :wh
AND on_hand - reserved - sell_buffer >= :qty;
-- Etkilenen satır sayısı 1 ise rezervasyon başarılı, 0 ise stok yetersiz
Rezervasyonun yaşam döngüsü:
- Sipariş oluşturulurken: Yukarıdaki sorguyla ayırın ve aynı işlemde bir reservations satırı yazın (durum pending, bitiş zamanı expires_at).
- Ödeme onaylanınca: Durumu koşullu bir sorguyla confirmed yapın (WHERE id = :id AND status = 'pending'); süre sınırı kalkar. Etkilenen satır 0 ise rezervasyonun süresi az önce dolmuştur; aşağıda anlatılan geç ödeme yoluna geçin.
- Süre dolarsa ya da sipariş iptal edilirse: Durum geçişini yine tek koşullu sorguyla yapın (süre dolumunda status = 'pending', iptalde status IN ('pending', 'confirmed') koşuluyla) ve rezerve adedi yalnızca etkilenen satır 1 ise geri bırakın. Ödeme onayı ile süre dolumu aynı anda çalışırsa yalnızca biri başarılı olur; böylece ödemesi alınmış siparişin stoğu serbest kalmaz. İptal ile süre dolumu çakıştığında da stok iki kez bırakılmaz.
- Sevkiyatta: Eldeki stoktan ve rezerve adetten aynı anda düşün, bir shipment hareketi yazın.
Rezervasyon süresi ödeme yöntemine göre değişir: kartlı ödemede dakikalar yeterliyken havale/EFT siparişlerinde süreyi iş kuralınız belirler. Bu süreyi ve süre dolunca siparişe ne olacağını satış koşullarınızda açıkça yazın. Süresi dolduktan sonra gelen ödemede stok hâlâ varsa yeniden ayırın; yoksa müşteriyi hemen bilgilendirip parayı iade edin ya da müşterinin onayıyla siparişi tarihli bir ön siparişe çevirin.
Varyantlar, setler ve birden fazla depo
Önceden paketlenip ayrı bir SKU olarak depolanmıyorsa set (bundle) ürünlerin kendi stoğu olmaz; satılabilir set adedi bileşenlerden hesaplanır. Her bileşenin satılabilir adedi setteki adedine bölünür, aşağı yuvarlanır ve bunların en küçüğü alınır. Örnek: bir kamp setinde 1 çadır ve 2 mat varsa, 7 çadır ve 10 mat ile en fazla min(7, 5) = 5 set satılabilir. Set satıldığında hareketler bileşenlere yazılır.Birden fazla depoda satılabilir stok depo bazında hesaplanır; siparişe hangi deponun atanacağı (en yakın depo, siparişi tek kolide toplayabilen depo, en eski stok) ayrı bir kuraldır. Mağaza stoğunu e-ticarete açıyorsanız (ör. mağazadan teslim, click and collect), mağazadaki sayım doğruluğu çoğunlukla depodakinden düşük olduğu için mağaza stoğuna daha büyük bir satış tamponu koyun.
Çok kanallı satış: site, pazaryerleri ve senkronizasyon
Aynı ürünü kendi sitenizde, Trendyol, Hepsiburada ya da Amazon'da satıyorsanız stok için tek bir doğruluk kaynağı (source of truth) olmalıdır: ERP, sipariş yönetim sistemi (OMS) ya da e-ticaret altyapınız. Kanallar bu kaynaktan beslenir; hiçbir kanalda stok elle düzeltilmez.- Olay tabanlı itme: Her stok değişikliğinde ilgili SKU için tüm kanallara bir güncelleme kuyruğa yazılır. Kısa sürede gelen değişiklikler birleştirilir, API hız sınırlarına uyulur, hata alan istekler artan beklemeyle (exponential backoff) yeniden denenir. Kanala fark (delta) yerine, gönderim anında okunan güncel satılabilir adedi mutlak sayı olarak gönderin; böylece yeniden denenen bir istek aynı adedi ikinci kez düşmez.
- Hızlı sipariş çekme: Pazaryeri siparişleri ne kadar geç çekilirse fazla satış riski o kadar artar. Webhook varsa kullanın, yoksa siparişleri sık aralıklarla çekin ve gelen siparişi hemen rezerve edin. Trendyol tarafındaki uç noktaları Trendyol API entegrasyonu yazımızda anlattık.
- Kanal tamponu: Senkronizasyon gecikmesini karşılamak için pazaryerine satılabilir stoktan birkaç adet eksik gönderin. Az kalan ürünlerde (ör. satılabilir stok 2 ve altı) ürünü yalnızca kendi sitenizde açık tutmak da bir seçenektir.
- Gece mutabakatı: Kanallardaki stoğu beklenen değerle karşılaştıran bir iş, olay akışında kaybolan güncellemeleri yakalar.
Güvenlik stoğu, yeniden sipariş noktası ve sipariş miktarı
Ne zaman ve ne kadar sipariş verileceği göz kararına değil, basit bir hesaba dayanmalıdır. Talebin dalgalı, tedarik süresinin sabit olduğu ve günlük satışların normal dağılıma uyup günden güne bağımsız olduğu varsayımıyla yaygın kullanılan formüller şunlardır:
Code:
Güvenlik stoğu (SS) = Z × σd × √L
Yeniden sipariş noktası (ROP) = d × L + SS
d : ortalama günlük satış (adet)
σd : günlük satışın standart sapması (adet)
L : tedarik süresi (gün)
Z : hizmet düzeyi katsayısı (%90 ≈ 1,28; %95 ≈ 1,645; %98 ≈ 2,05; %99 ≈ 2,33)
Buradaki hizmet düzeyi, bir tedarik döngüsünü stoksuz kalmadan geçirme olasılığıdır (cycle service level); talebin yüzde kaçının doğrudan stoktan karşılandığını gösteren karşılama oranı (fill rate) ile karıştırmayın. Hizmet düzeyini her üründe aynı da seçmeyin: %95'ten %99'a çıkmak güvenlik stoğunu yaklaşık %41 artırır (2,33 ÷ 1,645). Yüksek düzeyi çok satan ve kâr getiren ürünlere ayırmak sermayeyi daha verimli kullanır.
Tedarik süresi de dalgalanıyorsa genişletilmiş formül kullanılır: SS = Z × √(L × σd² + d² × σL²); burada σL, tedarik süresinin gün cinsinden standart sapmasıdır. Aynı örnekte σL = 2 gün olursa SS ≈ 1,645 × √(9 × 25 + 144 × 4) ≈ 47 adete çıkar. Yani tedarikçinin teslim tutarlılığı, talepteki dalgalanma kadar önemlidir. Kampanya dönemlerinde ve sezonluk ürünlerde bu formüller de tek başına yetmez; geçmiş kampanya verisi ve tedarikçinin gerçek teslim performansı hesaba katılmalıdır.
Sipariş miktarı için başlangıç noktası ekonomik sipariş miktarıdır (EOQ): Q = √(2 × D × S ÷ H). D yıllık talep (adet), S sipariş başına sabit maliyet (satın alma ekibinin emeği, nakliye, mal kabul), H ise bir adedi bir yıl elde tutmanın maliyetidir (sermaye, depo, sigorta, fire). Toplam maliyet optimum çevresinde yavaş değiştiği için EOQ'dan %20 sapmak, sipariş ve elde tutma maliyetlerinin toplamını %3'ten az artırır; sonucu koli içi adede, tedarikçinin asgari sipariş miktarına (MOQ) ya da fiyat kademelerine yuvarlamak bu yüzden genellikle sorun olmaz. Siparişi sabit günlerde veriyorsanız (ör. her pazartesi) sabit bir sipariş noktası yerine hedef stok düzeyi (order-up-to level) kullanılır: T = d × (R + L) + Z × σd × √(R + L). Burada R sipariş aralığıdır (gün); her siparişte stok pozisyonunu T'ye tamamlarsınız.
Önceliklendirme için ABC analizi kullanılır: ürünler ciroya katkısına göre sıralanır; cironun büyük kısmını (çoğunlukla yaklaşık %80'ini) getiren küçük grup A, sonrakiler B ve C olur. A ürünlerinde stoksuz kalmak pahalıdır; sayım ve tedarik takibi en sık onlarda yapılır.
İadeler, sayım ve muhasebeyle uyum
İade gelen ürünü doğrudan satılabilir stoğa eklemeyin. Önce satışa kapalı bir karantina konumuna (ör. ayrı bir warehouse_id) alın; kontrolde sağlam çıkanları return_restock hareketiyle satış stoğuna aktarın, hasarlıları karantinadan düzeltme (adjustment) hareketiyle fire olarak düşün. Kargo ve iade süreçlerinin entegrasyonunu kargo API yazımızda ele aldık.Yılda bir kez yapılan genel sayım, yıl içindeki kaymaları geç yakalar. Döngüsel sayımda (cycle counting) her gün ya da hafta küçük bir ürün grubu sayılır; A ürünleri daha sık, C ürünleri daha seyrek. Sayılan raftan aynı anda toplama yapılırsa sonuç bozulur: konumu kısa süreliğine toplamaya kapatın ya da sayım anındaki sistem değerini kaydedip aradaki hareketleri hesaba katın. Sayım farkı bir düzeltme hareketiyle ve gerekçesiyle kaydedilir. Sürekli fark çıkan ürünler süreçteki sorunu (yanlış toplama, kayıp, hatalı mal kabul) gösterir. Bilanço esasına göre defter tutan işletmelerde yıl sonu envanteri muhasebe açısından da gereklidir; e-ticaret stok kayıtlarınızın muhasebe kayıtlarıyla uyumlu olması için mali müşavirinizle birlikte çalışın.
İzlenecek metrikler
| Metrik | Hesap | Ne söyler |
|---|---|---|
| Fazla satış oranı | Stok nedeniyle iptal edilen sipariş ÷ toplam sipariş | Senkronizasyon ve rezervasyonun sağlığı |
| Stoksuz kalma oranı | Stoksuz geçen ürün-gün ÷ toplam ürün-gün | Tedarik ve yeniden sipariş ayarları |
| Stok devir hızı (inventory turnover) | Satılan malın maliyeti ÷ ortalama stok değeri | Sermayenin ne kadar hızlı döndüğü |
| Stok devir süresi (days of inventory) | 365 ÷ yıllık stok devir hızı (gün) | Ölü stok riski |
| Satılma oranı (sell-through rate) | Dönemde satılan ÷ dönemde gelen adet | Sezonluk ürünlerde alım doğruluğu |
| Sayım doğruluğu (inventory accuracy) | Farksız sayılan kalem ÷ sayılan kalem | Sistemdeki sayıya güvenilip güvenilemeyeceği |
Sık yapılan hatalar
- Tek bir stok sütunu tutmak ve rezerve adedi ayırmamak.
- Stoğu sepete eklemede düşmek ya da hem ödemede hem sevkiyatta düşerek iki kez saymak.
- "Önce oku, sonra yaz" ile rezervasyon yapmak: yoğun bir kampanyada aynı son ürün iki kez satılır.
- Pazaryerinde stoğu elle güncellemek: bir sonraki senkronizasyon ya da sipariş sayıları yeniden bozar.
- Kanallara mutlak adet yerine fark (delta) göndermek: yeniden denenen bir istek stoğu iki kez düşer.
- İadeleri kontrol etmeden satılabilir stoğa eklemek.
- Güvenlik stoğunu tüm ürünlerde aynı sabit sayı (ör. 5 adet) yapmak.
Sık sorulan sorular
Stok ne zaman düşülmeli: sepette mi, siparişte mi, ödemede mi?Sepette değil. Sipariş oluşturulurken süreli bir rezervasyon yapın, ödeme onayında rezervasyonu kalıcı hâle getirin ve eldeki stoğu sevkiyatta düşün. Böylece sitede gösterilen sayı doğru kalır, depodaki sayı da fiziksel gerçeği yansıtır.
Pazaryerinde neden stoktan fazla satış oluyor?
Çoğunlukla üç nedenin birleşimidir: siparişlerin geç çekilmesi, stok güncellemelerinin kuyrukta beklemesi ve kanal tamponunun olmaması. Sipariş çekme aralığını kısaltmak ve az kalan ürüne tampon koymak çoğu durumda sorunu belirgin biçimde azaltır.
Excel ile stok takibi yeterli mi?
Tek kanalda, az ürünle başlarken yeterli olabilir. Birden fazla satış kanalı, varyantlı ürünler ya da birden fazla depo devreye girdiğinde, eşzamanlı güncellemesi ve hareket kaydı olmayan bir tablo fazla satış ve sayım farkı üretir.
Güvenlik stoğunu hesaplamak için ne kadar veri gerekir?
Mevsimselliği olmayan ürünlerde birkaç aylık günlük satış verisi başlangıç için yeterlidir. Stoksuz kalınan günler talebi olduğundan düşük gösterir; bu günleri hesaptan çıkarın ya da ayrıca işaretleyin.
ERP ile e-ticaret sitesi arasında stok hangi yönde akmalı?
Doğruluk kaynağı hangisiyse ondan diğerlerine. Depo ve muhasebe ERP'deyse (ör. Logo, Mikro, Netsis) stok ERP'den siteye ve pazaryerlerine, siparişler de kanallardan ERP'ye akar. İki yönlü ve elle düzeltilen stok, senkronizasyon çakışmalarının en yaygın nedenidir.
Fazla satış olduysa ne yapmalı?
Önce ürünü taahhüt ettiğiniz teslim süresi içinde tedarik edip edemeyeceğinize bakın; Mesafeli Sözleşmeler Yönetmeliği'ne göre bu süre, tüketicinin isteği ya da kişisel ihtiyaçlarına göre hazırlanan mallar dışında, mal satışlarında otuz günü geçemez. Müşteriye durumu ve yeni tarihi hemen bildirin. Süresinde teslim edemezseniz müşteri sözleşmeyi feshedebilir ve tahsil edilen tüm ödemeler, fesih bildiriminin size ulaştığı tarihten itibaren on dört gün içinde iade edilmelidir. Pazaryeri siparişlerinde platformun kendi iptal kuralları da geçerlidir; somut durumlar için hukuk danışmanınıza başvurun.
Sonuç ve sonraki adımlar
- Eldeki, rezerve ve satılabilir stoğu ayırın; sitede ve kanallarda yalnızca satılabilir stoktan türetilen sayıyı gösterin.
- Stok değişikliklerini hareket kaydına çevirin ve gece mutabakatı kurun.
- Rezervasyonu tek koşullu sorguyla yapın; ödeme onayını, süre dolumunu ve iptali koşullu durum geçişleriyle yönetin.
- A grubu ürünler için güvenlik stoğu ve yeniden sipariş noktası hesaplayın, sonuçları birkaç ay izleyin.
- Fazla satış oranını haftalık takip edin; sıfıra yakın değilse önce sipariş çekme sıklığına ve kanal tamponuna bakın.
What a stock error costs
In e-commerce a stock figure is not just the count in the warehouse; it is a promise made at the same time on your own site, on marketplaces and on orders being picked. Get it wrong and the losses take three forms:- Overselling: selling items you do not have. The order is cancelled, the customer may not come back, and on marketplaces seller-caused cancellations also feed into your seller performance metrics. In Türkiye there is a legal side too: under Article 16 of the Distance Contracts Regulation (Mesafeli Sözleşmeler Yönetmeliği), goods being out of stock do not count as performance becoming impossible, so cancelling an order as "out of stock" carries legal risk.
- Stockouts: a product runs out just when it sells best. Ad spend is wasted, and the visibility the product had built up in search and marketplace listings can fade.
- Dead stock: capital tied up in items that do not sell, storage costs, and eventually clearing them at a discount.
Four numbers: on hand, reserved, available, incoming
A single "stock" column is behind most problems. Separate at least these four:| Concept | Definition | What changes it |
|---|---|---|
| On hand | Units physically in the warehouse | Goods receipt, shipment, return, count adjustment |
| Reserved | Units ordered but not yet shipped | Order, cancellation, reservation expiry, shipment |
| Available to sell | On hand − reserved − sell buffer | Calculated, never typed in |
| Incoming | Units ordered from a supplier but not yet received | Purchase order, goods receipt |
Data model: a ledger, not a counter
When a counter that says "stock = 17" turns out to be wrong, nobody can tell why. Write every change as a movement row instead; on hand is the sum of the movements. The examples use MySQL syntax:
SQL:
CREATE TABLE stock_movements (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
sku VARCHAR(64) NOT NULL,
warehouse_id INT NOT NULL,
qty INT NOT NULL, -- positive in, negative out
reason VARCHAR(32) NOT NULL, -- receipt, shipment, return_restock, adjustment, transfer
ref VARCHAR(64), -- order, purchase order or count number
created_by VARCHAR(64) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_sku_wh (sku, warehouse_id)
);
-- On hand = sum of movements
SELECT sku, warehouse_id, SUM(qty) AS on_hand
FROM stock_movements
GROUP BY sku, warehouse_id;
Reservations in checkout and the race condition
When two customers try to buy the last item in the same second, "read the stock, then decrement it" sells to both. Combine the check and the reservation in one conditional UPDATE:
SQL:
-- Reserve only if enough is available: one statement, no race
UPDATE stock_levels
SET reserved = reserved + :qty
WHERE sku = :sku
AND warehouse_id = :wh
AND on_hand - reserved - sell_buffer >= :qty;
-- 1 affected row means reserved, 0 means not enough stock
The life cycle of a reservation:
- When the order is created: reserve with the statement above and, in the same transaction, write a reservations row (status pending, with an expires_at time).
- When payment is confirmed: set the status to confirmed with a conditional update (WHERE id = :id AND status = 'pending'); the time limit no longer applies. If no row is affected, the reservation has just expired, so take the late-payment path described below.
- When it expires or the order is cancelled: make that status change with one conditional statement too (status = 'pending' for expiry, status IN ('pending', 'confirmed') for a cancellation) and release the reserved quantity only if exactly one row was affected. If payment confirmation and expiry run at the same moment, only one of them succeeds, so a paid order never loses its stock; and a cancellation that collides with expiry cannot release the stock twice.
- On shipment: decrement on hand and reserved together and write a shipment movement.
The reservation window depends on the payment method: minutes are enough for card payments, while for bank transfer orders your own business rule decides. State that window, and what happens when it runs out, in your terms of sale. If a payment arrives after the reservation expired, reserve again if stock is still there; otherwise tell the customer straight away and refund, or, with the customer's agreement, turn the order into a dated pre-order.
Variants, bundles and multiple warehouses
Unless a bundle is pre-packed and stored as its own SKU, it has no stock of its own; its availability is calculated from the components. Divide each component's available quantity by the number needed per bundle, round down, and take the smallest result. Example: a camping bundle holds 1 tent and 2 mats, so with 7 tents and 10 mats you can sell at most min(7, 5) = 5 bundles. When a bundle sells, the movements are written against the components.With several warehouses, availability is calculated per warehouse, and which warehouse fulfils an order (the nearest, the one that can ship it in a single parcel, the oldest stock) is a separate rule. If you expose store stock to online orders (click and collect, for example), count accuracy in stores is usually lower than in the warehouse, so give store stock a larger sell buffer.
Selling on several channels: site, marketplaces and sync
If you sell the same product on your own site and on Trendyol, Hepsiburada or Amazon, stock needs a single source of truth: your ERP, an order management system (OMS) or your store platform. Every channel is fed from it, and nobody corrects stock by hand on a channel.- Event-driven push: every stock change queues an update for that SKU to every channel. Changes that arrive close together are merged, API rate limits are respected, and failed requests are retried with exponential backoff. Send the channel the current available quantity, read at the moment of sending, as an absolute number rather than a delta, so a retried request cannot subtract the same units twice.
- Fast order pulls: the later you pull marketplace orders, the higher the risk of overselling. Use webhooks where they exist; otherwise pull orders at short intervals and reserve each one as soon as it arrives. We describe the Trendyol side in our Trendyol API integration article.
- Channel buffer: send marketplaces a few units less than your available stock to cover sync delays. For items running low (for example 2 or fewer available) keeping them on sale only on your own site is another option.
- Nightly reconciliation: a job that compares each channel's stock with the expected value catches updates lost in the event stream.
Safety stock, reorder point and order quantity
When and how much to order should come from a simple calculation, not a hunch. Assuming variable demand, a fixed lead time, and daily sales that are normally distributed and independent from one day to the next, the commonly used formulas are:
Code:
Safety stock (SS) = Z × σd × √L
Reorder point (ROP) = d × L + SS
d : average daily sales (units)
σd : standard deviation of daily sales (units)
L : lead time (days)
Z : service level factor (90% ≈ 1.28; 95% ≈ 1.645; 98% ≈ 2.05; 99% ≈ 2.33)
The service level here is the probability of getting through one replenishment cycle without a stockout (cycle service level); do not confuse it with the fill rate, the share of demand served straight from stock. Nor should one service level apply to everything: going from 95% to 99% raises safety stock by about 41% (2.33 ÷ 1.645), so reserving high levels for best-selling, profitable items uses capital better.
If the lead time varies as well, use the extended formula SS = Z × √(L × σd² + d² × σL²), where σL is the standard deviation of the lead time in days. In the same example, σL = 2 days pushes SS to about 1.645 × √(9 × 25 + 144 × 4) ≈ 47 units: a supplier's delivery consistency matters as much as swings in demand. During campaigns and for seasonal items even these formulas are not enough on their own; bring in past campaign data and the supplier's actual delivery record.
For how much to order, the economic order quantity (EOQ) is the usual starting point: Q = √(2 × D × S ÷ H), where D is annual demand in units, S the fixed cost per order (purchasing effort, freight, goods receipt) and H the cost of holding one unit for a year (capital, storage, insurance, shrinkage). Total cost changes slowly around the optimum, so ordering 20% more or less than the EOQ raises the sum of ordering and holding costs by less than 3%; rounding to case packs, the supplier's minimum order quantity (MOQ) or price breaks is therefore usually fine. If you order on fixed days (every Monday, say), use an order-up-to level instead of a fixed reorder point: T = d × (R + L) + Z × σd × √(R + L), where R is the review interval in days, and top the inventory position up to T with each order.
ABC analysis helps you prioritise: rank products by revenue contribution; the small group that brings in most of the revenue (often around 80%) is A, the rest B and C. Stockouts on A items are expensive, so they get the most frequent counts and the closest supply tracking.
Returns, counting and keeping accounting in line
Do not put returned items straight back into available stock. Book them into a quarantine location that does not count towards availability (a separate warehouse_id, for example); after inspection, move the sound ones to sellable stock with a return_restock movement and write the damaged ones off from quarantine with an adjustment movement. We cover integrating shipping and returns in our cargo API article.A once-a-year full count catches drift late. With cycle counting you count a small group of products every day or week: A items more often, C items less often. Picking from a location while it is being counted spoils the result, so either block the location for picking briefly or record the system figure at the moment of counting and account for the movements in between. Count differences are booked as adjustment movements with a reason, and products that keep showing differences point to a process problem (wrong picks, losses, sloppy goods receipt). In Türkiye, businesses keeping balance-sheet-basis books also need a year-end inventory for accounting; work with your accountant so that your e-commerce stock records match the books.
Metrics to watch
| Metric | Calculation | What it tells you |
|---|---|---|
| Oversell rate | Orders cancelled for lack of stock ÷ all orders | Health of sync and reservations |
| Stockout rate | Product-days out of stock ÷ all product-days | Supply and reorder settings |
| Inventory turnover | Cost of goods sold ÷ average inventory value | How fast capital turns over |
| Days of inventory | 365 ÷ annual inventory turnover | Dead stock risk |
| Sell-through rate | Units sold ÷ units received in the period | Buying accuracy for seasonal items |
| Inventory accuracy | Lines counted without a difference ÷ lines counted | Whether the system figure can be trusted |
Common mistakes
- Keeping a single stock column with no separate reserved quantity.
- Decrementing stock when an item is added to the cart, or decrementing at payment and again at shipment.
- Reserving with "read, then write": in a busy campaign the same last item sells twice.
- Updating stock by hand on a marketplace: the next sync or the next order breaks the figures again.
- Sending channels deltas instead of absolute quantities: a retried request subtracts the stock twice.
- Putting returns back into available stock without inspection.
- Using one fixed safety stock (say 5 units) for every product.
Frequently asked questions
When should stock be decremented: in the cart, at the order or at payment?Not in the cart. Create a time-limited reservation when the order is placed, make it permanent when payment is confirmed, and decrement on hand at shipment. The figure on your site stays correct and the warehouse figure matches physical reality.
Why does overselling happen on marketplaces?
Usually because of three things together: orders pulled late, stock updates waiting in a queue, and no channel buffer. Shortening the order pull interval and buffering low-stock items cuts it down considerably in most cases.
Is a spreadsheet good enough for inventory tracking?
It can be when you start on one channel with a small catalogue. Once there are several sales channels, products with variants or more than one warehouse, a sheet without concurrent updates or a movement history produces overselling and count differences.
How much data do I need to calculate safety stock?
For non-seasonal products a few months of daily sales are enough to start. Days spent out of stock make demand look lower than it was; exclude them from the calculation or flag them separately.
Which way should stock flow between the ERP and the online store?
From whichever system is the source of truth to the others. If warehouse and accounting live in the ERP (Logo, Mikro or Netsis in many Turkish businesses), stock flows from the ERP to the site and the marketplaces, and orders flow from the channels into the ERP. Two-way stock with manual corrections is the most common cause of sync conflicts.
What should I do after an oversell?
First check whether you can source the item within the delivery time you promised; in Türkiye the Distance Contracts Regulation caps that time at thirty days for goods, except goods prepared to the consumer's request or personal needs. Tell the customer what happened and give a new date straight away. If you cannot deliver in time, the customer may terminate the contract, and everything collected must be refunded within fourteen days of the termination notice reaching you. Marketplace orders are also subject to the platform's own cancellation rules; take specific cases to your legal adviser.
Conclusion and next steps
- Separate on hand, reserved and available, and show only figures derived from available stock on your site and channels.
- Turn stock changes into ledger movements and set up a nightly reconciliation.
- Reserve with a single conditional statement, and handle payment confirmation, expiry and cancellation as conditional status transitions.
- Calculate safety stock and reorder points for your A items and watch the results for a few months.
- Track the oversell rate weekly; if it is not close to zero, look at the order pull interval and the channel buffer first.
Last edited: