Bayilerin ve kurumsal müşterilerin kendi özel fiyatlarıyla sipariş verdiği bir B2B portalı dışarıdan bakınca basit bir e-ticaret sitesine benzer: ürün listesi, sepet, onay butonu. Ama arka tarafta durum çok farklıdır. Stok, fatura, cari hesap ve risk limiti ERP'dedir; iletişim geçmişi, fırsatlar ve upsell planı CRM'dedir; portal ise ikisinin arasında, her iki sistemin de doğru kabul ettiği tek bir gerçeği müşteriye göstermeye çalışır. Ben, Koray Yalçın olarak CRM mimarisi, lead yönetimi ve pazarlama otomasyonu üzerine çalışırken en çok zaman kaybettiren hataların arayüzde değil, tam bu entegrasyon katmanında ortaya çıktığını gördüm.
Bu yazıda B2B portal projesini iş tarafından değil, siparişi ERP'ye ulaştıracak kodu yazan geliştiricinin gözünden ele alıyorum: neden portalın ERP veritabanına doğrudan bağlanmaması gerektiği, çift sipariş nasıl önlenir, outbox deseni ne işe yarar, kredi limiti kontrolü nerede yapılmalı ve fiyat listeleri nasıl önbelleğe alınır. Belirli bir ERP'yi (SAP, Logo, Mikro) ya da belirli bir mesaj kuyruğunu savunmuyorum; ilkeler hepsinde aynı.
1. İlk kural: Portal ERP veritabanına SQL atmaz
Küçük ekiplerde en hızlı çözüm gibi görünen şey, portal uygulamasının ERP'nin veritabanına bir okuma-yazma kullanıcısıyla bağlanmasıdır. İlk hafta çalışır. Sonra şu sorunlar birer birer gelir:
- Şema bağımlılığı: ERP güncellemesi bir tablo adını ya da alan tipini değiştirdiğinde portal sessizce bozulur.
-
İş kurallarının atlanması: ERP'nin kendi arayüzünden girilen siparişte çalışan doğrulamalar, tetikleyiciler ve numaralandırma mantığı doğrudan
INSERTile tamamen devre dışı kalır. - Performans: Yoğun saatte portaldan gelen fiyat sorguları, muhasebe ekibinin gün sonu raporlarıyla aynı veritabanı kaynaklarını paylaşır.
- Güvenlik: İnternete açık bir uygulamanın, şirketin finansal çekirdeğine geniş yetkili bir bağlantısı olur.
Doğru yapı, portal ile ERP arasına bir entegrasyon katmanı koymaktır. Bu katman ERP'nin resmi API'sini, web servisini ya da onaylı içe aktarma mekanizmasını kullanır; portal ise yalnızca bu katmanla konuşur. Arada bir mesaj kuyruğu (RabbitMQ, Kafka ya da bulut sağlayıcınızın yönetilen kuyruğu) bulunması, ERP yavaşladığında veya bakımdayken siparişlerin kaybolmadan beklemesini sağlar.
2. Siparişin yaşam döngüsünü baştan tanımlayın
Kod yazmadan önce bir siparişin hangi durumlardan geçebileceğini netleştirmek, sonraki bütün tartışmaları kısaltır. Tipik bir durum makinesi şöyle görünür:
TASLAK -> GONDERILDI -> ERP_KUYRUGUNDA -> ERP_ONAYLADI -> SEVK_EDILDI -> FATURALANDI
\-> FINANS_ONAYI_BEKLIYOR -> (ONAY) -> ERP_KUYRUGUNDA
\-> REDDEDILDI
ERP_KUYRUGUNDA -> ERP_HATASI -> (yeniden deneme) -> ERP_KUYRUGUNDA
Burada önemli olan iki şey var. Birincisi, portal siparişi "gönderildi" diye işaretlediği anda ERP'de sipariş oluşmuş değildir; müşteriye gösterilen ifade de buna uygun olmalıdır ("Siparişiniz alındı, onay bekleniyor" gibi). İkincisi, her durum geçişi kaydedilmelidir. Bir bayi "siparişim nerede?" diye aradığında müşteri temsilcisinin bakacağı yer bu geçmiştir.
3. Çift siparişi önlemek: Idempotency anahtarı
B2B'de çift sipariş, B2C'deki kadar masum değildir. Tek bir sipariş satırı birkaç palet hammadde olabilir. Çift kaydın en yaygın sebepleri bellidir: kullanıcı butona iki kez basar, mobil ağ yanıtı yarıda keser ve uygulama isteği tekrarlar, kuyruk tüketicisi mesajı işledikten sonra onay vermeden çöker ve mesaj yeniden teslim edilir.
Çözüm, her sipariş için istemci tarafında üretilen bir idempotency anahtarıdır. Sepet onay ekranı açıldığında bir UUID üretilir ve sipariş isteğiyle birlikte gönderilir. Sunucu tarafında bu anahtar benzersiz kısıtla saklanır:
CREATE TABLE portal_orders (
id BIGSERIAL PRIMARY KEY,
idempotency_key UUID NOT NULL UNIQUE,
customer_code TEXT NOT NULL,
status TEXT NOT NULL,
erp_order_no TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
Aynı anahtarla ikinci istek geldiğinde yeni sipariş oluşturulmaz; ilk siparişin durumu döndürülür. Aynı mantık entegrasyon katmanının ERP'ye yazdığı noktada da gerekir. ERP'nin sipariş kaydında harici referans alanı varsa (çoğunda "belge no", "harici referans" ya da benzeri bir alan bulunur) portal sipariş kimliği oraya yazılır ve ERP'ye göndermeden önce bu referansla kayıt olup olmadığı kontrol edilir. Böylece kuyruk mesajı iki kez işlense bile ERP'de tek sipariş oluşur.
4. Outbox deseni: Veritabanı ile kuyruk arasındaki boşluk
Klasik hata şudur: uygulama siparişi kendi veritabanına yazar, ardından kuyruğa bir mesaj atar. Veritabanı işlemi başarılı olur ama kuyruk çağrısı ağ hatası verirse sipariş portalda görünür, ERP'ye hiç gitmez. Ters sırada yaparsanız bu kez ERP'ye giden ama portalda olmayan bir sipariş oluşabilir.
Transactional outbox deseni bu boşluğu kapatır. Sipariş kaydı ile "gönderilecek mesaj" kaydı aynı veritabanı işlemi içinde yazılır:
def submit_order(conn, order, idempotency_key):
with conn.transaction():
order_id = insert_order(conn, order, idempotency_key, status="GONDERILDI")
conn.execute(
"INSERT INTO outbox (aggregate_id, event_type, payload) VALUES (%s, %s, %s)",
(order_id, "OrderSubmitted", to_json(order)),
)
return order_id
Ayrı bir yayıncı süreç outbox tablosunu düzenli okur, mesajları kuyruğa iletir ve başarıyla iletilenleri işaretler. Yayıncı çökerse mesaj tabloda bekler; tekrar ayağa kalktığında kaldığı yerden devam eder. Bu yöntem "en az bir kez teslim" garantisi verir; bu yüzden bir önceki bölümdeki idempotency kontrolü zorunlu bir eştir. İkisi birlikte, pratikte "tam bir kez etki" sonucunu üretir.
5. Kredi limiti kontrolü nerede yapılmalı?
B2B portalının perakende e-ticaretten en belirgin farkı, ödemenin çoğu zaman sipariş anında değil vadeli olarak yapılmasıdır. Bu da her siparişte müşterinin açık hesap riskini, vadesi geçmiş borcunu ve tanımlı kredi limitini kontrol etmeyi gerektirir.
Bu kontrolün iki katmanda yapılması sağlıklıdır:
- Portal tarafında ön kontrol: Sepet onay ekranında entegrasyon katmanı üzerinden ERP'den güncel risk bilgisi alınır. Limit aşılıyorsa kullanıcıya baştan söylenir; sipariş "Finans Onayı Bekliyor" durumuna gideceği açıkça belirtilir.
- ERP tarafında kesin kontrol: Asıl karar ERP'ye yazılırken verilir, çünkü ön kontrol ile yazma arasında başka bir sipariş ya da tahsilat bakiyeyi değiştirmiş olabilir.
Ön kontrol için ERP'ye her sepet güncellemesinde sorgu atmak gerekmez. Risk bilgisini kısa süreli (örneğin birkaç dakikalık) önbellekte tutmak ve yalnızca onay adımında taze veri çekmek hem ERP'yi korur hem kullanıcı deneyimini hızlandırır. Finans onayına düşen siparişler için CRM'de ilgili müşteri temsilcisine otomatik görev açmak da iyi bir pratiktir; temsilci müşteriyi arayıp tahsilatı konuşabilir ve sipariş beklemede çürümez.
6. Kademeli fiyat listeleri ve önbellek
Her bayinin kendi iskonto grubu, hacim kademeleri ve bazen ürün bazlı özel fiyatları vardır. Portal her ürün listesinde bu fiyatları ERP'den anlık hesaplatırsa sayfa yavaşlar; tamamen önbellekten gösterirse yanlış fiyatla sipariş alma riski doğar.
İşe yarayan yaklaşım şudur:
- Fiyat listeleri (price book) ve iskonto kuralları entegrasyon katmanı tarafından ERP'den periyodik olarak çekilip portalın okuma modeline yazılır. Değişiklik olayı yayınlayabilen bir ERP'de bu, olay tabanlı da yapılabilir.
- Listeleme ve arama ekranları bu okuma modelinden beslenir.
- Sepet onayı sırasında son fiyat ERP'den doğrulanır. Fark varsa kullanıcıya gösterilir ve onay yeniden istenir.
- Her fiyat kaydında "geçerlilik başlangıcı" ve "son senkron zamanı" tutulur. Senkron belirli bir süreden uzun gecikirse sistem uyarı üretir.
Bu yapı, kampanya dönemlerinde fiyatların toplu değiştiği günlerde özellikle önem kazanır. Kullanıcı eski fiyatı görüp siparişi verdiğinde yaşanacak tartışma, birkaç saniyelik ek doğrulamadan çok daha pahalıdır.
7. CRM'e ne gider, ne gitmez?
Portal, ERP ve CRM aynı anda konuştuğunda en sık yapılan hata, her şeyi her yere kopyalamaktır. Pratikte iyi işleyen ayrım şöyledir:
- ERP'de kalır: stok, fatura satırları, cari hareketler, risk hesaplaması. Bunların ana kaynağı ERP'dir.
- CRM'e özet olarak gider: sipariş toplamı, sipariş sıklığı, son sipariş tarihi, ürün kategorisi dağılımı, finans onayına düşen siparişler.
- CRM'de doğar: iletişim geçmişi, fırsatlar, upsell ve çapraz satış planları, müşteri memnuniyeti notları.
Bu özet veriler CRM'de çok değerli tetikleyicilere dönüşür. Örneğin düzenli olarak ayda bir sipariş veren bir bayi kırk beş gündür sipariş vermediyse temsilciye görev açılabilir. Bu, müşteri kaybını erken yakalamanın en ucuz yollarından biridir ve verinin tamamını değil yalnızca doğru özeti taşımayı gerektirir.
8. Gözlemlenebilirlik: Kaybolan siparişi beş dakikada bulmak
Entegrasyon katmanı kara kutu olursa her sorun bir suçlama oyununa döner: portal ekibi ERP'yi, ERP ekibi ağı, ağ ekibi kuyruğu suçlar. Bunu önlemek için baştan şunları koyun:
- Her siparişe portal tarafında üretilen bir korelasyon kimliği atayın ve bu kimliği portal logundan kuyruk mesajına, oradan ERP isteğine kadar taşıyın.
- Kuyrukta belirli sayıda başarısız denemeden sonra mesajı bir hata kuyruğuna (dead letter queue) alın ve bunun için alarm kurun. Sessizce bekleyen bir hata kuyruğu, en tehlikeli kuyruktur.
- "Gönderildi ama belirli süredir ERP onayı yok" durumundaki siparişleri listeleyen basit bir panel hazırlayın. Operasyon ekibi sabah ilk iş bu listeye bakmalıdır.
- ERP hata mesajlarını ham haliyle değil, sınıflandırarak saklayın: geçici hata (zaman aşımı, kilit), veri hatası (tanımsız ürün kodu, birim uyumsuzluğu), iş kuralı hatası (limit, bloke cari). Yeniden deneme yalnızca geçici hatalar için anlamlıdır.
9. Canlıya geçişten önce veri hijyeni
Entegrasyonun kalitesi, ERP'deki ana verinin kalitesini geçemez. Portal açılmadan önce ürün kodlarının, barkodların, birim çevrimlerinin (koli, adet, paket) ve cari kodlarının standartlaştırılması gerekir. Aynı ürünün iki farklı kodla tutulduğu ya da birim tanımının eksik olduğu bir katalogda, en iyi tasarlanmış idempotency ve outbox yapısı bile yanlış siparişi hatasız şekilde ERP'ye taşır.
Geçişi de kademeli yapmak mantıklıdır: önce teknolojiye yatkın, sadık küçük bir bayi grubuyla pilot yapılır, durum geçişleri ve hata kuyruğu birkaç hafta izlenir, sonra tüm ağa açılır. Pilot dönemde toplanan hata sınıfları, entegrasyonun gerçekte nerede zorlandığını gösteren en dürüst veridir.
Sık Sorulan Sorular (SSS)
Mesaj kuyruğu küçük bir portal için gereksiz karmaşıklık değil mi?
Günde birkaç sipariş alan bir yapıda kuyruk yerine outbox tablosunu doğrudan okuyan bir arka plan işi yeterli olabilir. Önemli olan kuyruğun kendisi değil, siparişin ERP geçici olarak erişilemezken kaybolmamasıdır.
Idempotency anahtarını sunucu mu üretmeli, istemci mi?
İstemci üretmelidir; çünkü amaç, aynı kullanıcı eyleminin tekrarlanan isteklerini tanımaktır. Sunucu yalnızca anahtarı benzersiz kısıtla saklar ve tekrar eden istekte ilk sonucu döndürür.
ERP harici referans alanı desteklemiyorsa ne yapılır?
Entegrasyon katmanı kendi eşleme tablosunu tutar: portal sipariş kimliği ile ERP belge numarası. ERP'ye yazmadan önce bu tabloya bakılır, yazdıktan hemen sonra tablo güncellenir. Bu durumda yazma ile eşleme arasındaki kısa boşluk için ERP tarafında periyodik bir mutabakat kontrolü eklemek iyi olur.
Fiyatları tamamen gerçek zamanlı göstermek mümkün değil mi?
Mümkün, ama ERP'nin hesaplama yükünü ve yanıt süresini portalın her sayfa açılışına bağlar. Okuma modeli ile listeleme, onayda kesin doğrulama yaklaşımı çoğu durumda hız ve doğruluk arasındaki en sağlıklı dengedir.
Kredi limiti aşıldığında sipariş tamamen reddedilmeli mi?
Çoğu B2B ilişkisinde hayır. Siparişi "Finans Onayı Bekliyor" durumuna almak ve ilgili temsilciye görev açmak, hem satışı kaybetmez hem riski kontrol altında tutar.
Bu yapıyı CRM tarafında nasıl değerlendirmeliyim?
Sipariş özetlerini CRM'e taşıyıp sipariş sıklığındaki düşüşleri, finans onayına düşen siparişleri ve kategori değişimlerini tetikleyici olarak kullanın. Portal yalnızca sipariş kanalı değil, müşteri davranışını ölçen bir veri kaynağı haline gelir.
Koray Yalçın; lead yönetimi, CRM mimarisi, dijital pazarlama ve yapay zekâ entegrasyonları üzerine çalışıyor. B2B ve gayrimenkul satış ekipleri için reklamdan CRM'e, CRM'den operasyon sistemlerine uzanan veri akışları kuruyor.













