Rutıx
İçindekiler

Fiyatlandırma

Bir satırın fiyatı, sırayla değerlendirilen fiyat listelerinden ilk eşleşenden gelir. Sonuç yalnızca sayı değildir: hangi listelerin bakıldığını, her birinin neden atlandığını ve hangi kırılımın tuttuğunu gösteren sıralı bir iz de döner.

Dağıtıcının arka ofisinde en çok zaman alan soru şudur: “bu dükkân bu koliye neden ₺469,20 ödüyor?” Cevabı bulmak, kimin hangi listeye bağlı olduğunu, hangi kampanyanın o gün yürürlükte olduğunu ve hangi miktar kırılımının tuttuğunu elle takip etmeyi gerektirir. Rutix bu izi hesaplamanın kendisinden üretir — yani açıklama, temsilciye gösterilen fiyattan sapmaz, çünkü ikisi aynı kod yolundan çıkar.

Fiyat listesi #

Bir fiyat listesi başlığı şunları taşır:

AlanAnlamı
Ad ve kodKod kiracı içinde tekildir; ikinci bir liste aynı kodu alamaz.
Para birimiVarsayılan TRY.
GeçerlilikBaşlangıç tarihi ve isteğe bağlı bitiş tarihi. Bitiş boşsa liste açık uçludur. Bitiş, başlangıçtan önce olamaz.
KanalDoluysa liste yalnızca o kanaldaki müşteriler için aday olur.
Organizasyon birimiDoluysa liste o distribütöre/şubeye bağlanır.
ÖncelikTam sayı. Aynı katmandaki listeler arasında büyük olan kazanır.
Varsayılan mıKiracı başına tek bir varsayılan liste olabilir. Bir listeyi varsayılan yapmak diğerlerinin varsayılanlığını kaldırır.
DurumTaslak, aktif ya da arşivlenmiş. Yalnızca aktif listeler aday olur.

Adaylar nasıl toplanır #

Bir müşteri–ürün–birim–tarih sorgusu için önce aday listeler toplanır. Bir liste aday olabilmek için aktif olmalı, sorgu tarihinde geçerli olmalı ve şu dördünden en az birini sağlamalıdır: müşterinin kendisine atanmış liste olmak, müşterinin kanalıyla eşleşmek, müşterinin organizasyon birimiyle eşleşmek ya da varsayılan liste olmak.

Her aday, hangi sebeple aday olduğuna göre bir katmana yerleşir. Sıra bu dört maddeyle aynıdır ve ilk eşleşen kazanır — bir liste hem müşteriye atalı hem varsayılansa, müşteri katmanında sayılır.

Sıralama ve eşitlik bozma #

Adaylar şu sırayla dizilir:

  1. Katman. Müşteriye özel liste → kanal listesi → distribütör listesi → genel liste.
  2. Öncelik. Aynı katmanda büyük öncelik önce gelir.
  3. Ad. Kalan eşitlik ada göre bozulur, böylece sonuç satır sırasına bağlı kalmaz ve iki çalıştırma aynı cevabı verir.

Katman öncelikten önce geldiği için, müşteriye atanmış bir liste, önceliği daha yüksek bir varsayılan listeyi yener. Bu bilinçli: bir müşteriye özel liste atamak, o müşteriyi genel tarifeden çıkarmak demektir; genel listenin önceliğini yükseltmek bunu geri almamalıdır.

Motor sırayla ne yapar #

  1. 1

    Hiç aday yoksa

    İz tek bir adım taşır: price.no_candidates. Bu müşteriye hiçbir fiyat listesi uygulanmıyor demektir.
  2. 2

    Aday sırayla denenir

    Sorgu tarihinde geçerli olmayan bir aday price.list_not_effective ile atlanır ve iz o tarihi de yazar.
  3. 3

    Miktar kırılımı aranır

    Listede o ürün ve o birim için satır varsa, istenen miktarın karşıladığı en yüksek kırılım seçilir. Kırılımlı eşleşme price.matched_at_break, kırılımsız eşleşme price.matched koduyla yazılır ve motor orada durur.
  4. 4

    Yoksa taban birimden türetilir

    Liste istenen birimi fiyatlamıyorsa ve ürünün o birim için birden büyük bir katsayısı varsa, fiyat taban birimden türetilir: price.derived_from_base_unit. Türetme her aday liste için, bir sonrakine geçmeden önce denenir.
  5. 5

    Bu liste bu ürünü taşımıyorsa

    price.no_entry yazılır ve sıradaki adaya geçilir. Bütün adaylar tükenirse iz price.exhausted ile kapanır.

Miktar kırılımları #

Bir fiyat satırı ürün, birim, fiyat ve en az miktar taşır. En az miktarı sıfır olan satır taban fiyattır. Kendi tarih penceresi de olabilir, yani liste başlığından bağımsız olarak bir kırılım belli bir tarih aralığında çalıştırılabilir.

Seçim kuralı: istenen miktarın karşıladığı kırılımlar arasında en az miktarı en yüksek olan kazanır. En az miktarları eşitse düşük fiyat kazanır — veri girişinden kalan bir çift kayıt asla müşteriye pahalıya patlamaz. Hiçbir kırılım karşılanmıyorsa taban fiyat kullanılır.

Yazma tarafında aynı liste, ürün, birim ve en az miktar için ikinci bir satır reddedilir. Aksi hâlde “iki fiyattan ucuzu tesadüfen kazanır”, ve hangisinin kazandığı satır sırasına bağlı olur — bu ürünün karşı durduğu belirsizliğin ta kendisi.

Birimler: ADET, KOLİ, PALET #

Bir ürün adetle sayılır, koliyle sipariş edilir ve paletle taşınır. Aradaki katsayı her fiyatın, her stok hareketinin ve her promosyon eşiğinin üzerinden hesaplandığı sayıdır. On iki kat yanlış olması bir yuvarlama hatası değildir ve faturaya kadar görünmez — bu yüzden ürün formu birim tablosunun etrafına kurulmuştur.

Bir liste yalnızca adet fiyatını taşıyorsa koli fiyatı taban fiyat × katsayı ile türetilir. Türetmeden önce kırılım araması taban birime çevrilmiş miktarla yapılır, yani adet bazlı kırılımlar da doğru değerlendirilir. Türetme tek yönlüdür: koli fiyatından bölerek adet fiyatı üretilmez.

“Bu fiyat neden bu” #

GET /pricing/explain çözülen fiyatı ve izin tamamını döner. Panelde bu iz numaralı bir liste olarak gösterilir; aynı iz, satış anında sipariş satırına da yazılır.

İzin her adımı bir kod, o koda ait değerler ve hesaplandığı andaki metin taşır. Cümle istemcide, okuyanın dilinde kurulur. Bunun sebebi pratiktir ve bu üründe birden fazla yerde tekrarlanmıştır: bugün donmuş bir cümle yarın başka bir dilde gösterilemez, ve bir fiyat itirazı aylar sonra tam olarak bu kaydın üzerinden çözülür.

Rutix Yönetim — Fiyat denetiminde bir müşteri ve bir ürün seçiliyor; motorun sırayla değerlendirdiği listeler, hangisinin neden atlandığı ve hangi kırılımın tuttuğu adım adım dönüyor. Çalışan üründen kaydedildi; 10 saniye, sessiz.
KodNe demekTaşıdığı değerler
price.no_candidatesBu müşteriye hiçbir fiyat listesi uygulanmıyor.—
price.list_not_effectiveListe aday ama sorgu tarihinde geçerli değil.liste adı, tarih
price.matchedBu listede bu ürün ve birim için fiyat bulundu.liste adı, birim, fiyat, para birimi
price.matched_at_breakMiktar kırılımı tuttu.liste adı, birim, fiyat, para birimi, en az miktar
price.derived_from_base_unitBu birimin fiyatı yok; taban birimden türetildi.liste adı, birim, taban birim, taban fiyat, katsayı, sonuç
price.no_entryListe geçerli ama bu ürün/birim için satırı yok.liste adı, birim
price.exhaustedBütün adaylar bakıldı, hiçbiri bu ürünü taşımıyor.—
GET /pricing/explain?customerId=<müşteri>&productId=<ürün>&unit=KOLI&quantity=10

{
  "unitPrice": 469.20,
  "currency": "TRY",
  "priceListName": "Marmaris HORECA 2026",
  "source": "channel",
  "derivedFromBaseUnit": false,
  "trace": [
    { "order": 1, "code": "price.list_not_effective", "matched": false,
      "values": { "listName": "Yaz Tarifesi", "onDate": "2026-08-20" } },
    { "order": 2, "code": "price.matched_at_break", "matched": true,
      "values": { "listName": "Marmaris HORECA 2026", "unit": "KOLI",
                  "price": 469.20, "currency": "TRY", "minQuantity": 10 } }
  ]
}
Kısaltılmış bir açıklama cevabı. Türkçe cümle bu koddan ve değerlerden istemcide kurulur.

Yazarken reddedilenler #

Fiyat listesi yazma uçları, temiz kaydedilip sonra hiçbir şey yapmayan veriyi reddeder — bulunması bir gün süren hata türü budur:

  • Başka bir listenin kullandığı kod.
  • Başlangıcından önce biten geçerlilik penceresi.
  • Negatif fiyat.
  • Ürünün satılmadığı bir birim için fiyat — hiç eşleşmez ve belirtisi, birinin fiyatladığından emin olduğu bir satırda “fiyat bulunamadı” olur.
  • Aynı miktar kırılımına ikinci bir fiyat.
  • KOLİ’yi iki kez listeleyen bir ürün, ya da sıfır birim katsayısı.