Fişe Ek Alanlar — receiptExtras ⏳ Yakında

Kapanış gate'i (table.close / packet.close) allow yanıtında receiptExtras dizisi dönerse, öğeler kapanış yazılmadan ÖNCE adisyon dokümanına işlenir ve fişe basılabilir hale gelir. Karar ile veri aynı yanıtta gelir — belgeyi bağlamak için ikinci bir API çağrısı gerekmez. Tipik kullanım: Almanya KassenSichV / TSE mali bloğu, e-arşiv belge numarası, sadakat/kampanya satırı.

← Hook'lar (Akış Kontrolü) · table.close · packet.close

Yayına hazırlanıyor. Alan, backend dağıtımı tamamlandığında etkinleşir. Yeni scope yok, yeni uç yok, manifest alanı yok — sahiplik mevcut capability scope'unuzdan türetilir. Bu bir satışa yazma ucu değildir (§ Katman 1).

Sözleşme

Gate isteği değişmedi (bkz. Action Hook referansı). Yanıta yalnız receiptExtras eklendi:

allow + receiptExtras
{
  "decision": "allow",
  "receiptExtras": [
    { "key": "tse.qr",               "type": "qr",   "value": "V0;…" },
    { "key": "tse.txNumber",         "type": "text", "label": "Beleg-Nr",   "value": "366" },
    { "key": "tse.signatureCounter", "type": "text", "label": "Sig-Zähler", "value": "774" },
    { "key": "tse.timeStart",        "type": "text", "label": "TSE-Start",  "value": "1785438065" },
    { "key": "tse.status",           "type": "text", "value": "signed" }
  ]
}

{ "data": { … } } sarmalı da kabul edilir (mevcut hook davranışı).

Öğe şeması

AlanTipZorunluKural
keystringevet≤64; a-zA-Z0-9_- segmentleri, nokta ile ayrılır (tse.qr). Namespace sahipliğine tabidir.
type'text' | 'qr'hayırBilinmeyen değer öğeyi DÜŞÜRMEZ — güvenli default text uygulanır.
valuestringevetDAİMA metin, 1–2000 karakter. Sayı göndermeyin, string gönderin.
labelstringhayır≤64 — fişte değerin başına basılacak etiket (Beleg-Nr).
verifiedbooleanplatform üretirSahiplenilmiş namespace + yetki doğrulandıysa platform ekler. Eklenti gönderemez (gönderilirse yok sayılır).

type değerleri:

  • text — Metin — fişe düz satır olarak basılır (label varsa başına eklenir)
  • qr — QR — fişe QR kodu olarak basılır (ör. TSE doğrulama verisi)
value neden hep metin? Bu veri fişe basılan gösterim verisidir, hesaplama verisi değil. Beleg-Nr, Sig-Zähler ve epoch değerleri metin taşındığı için int32/precision taşması diye bir sorun doğmaz — TSE'den ne geldiyse fişe o basılır. Sayı göndermeyin, string gönderin.

Katman 1 — belgeye yazılan tek anahtar

Gate yanıtındaki diğer alanlar (decision, message, level, display) protokol alanlarıdır: akışı yönetir ve kasiyere bildirim gösterir. Adisyon dokümanına yazılan tek alan receiptExtras'tır.

Tutar, ödeme ve satır alanları bu yola hiç giremez. Platformun yazdığı alan adı sabittir; verdiğiniz key yalnız dizi öğesinin içinde yaşar — doküman kökünde alan açamaz. {"key":"total"} göndermek adisyon tutarını değiştirmez, yalnızca total adlı bir gösterim öğesi üretir (ve verified işareti almaz).

Adisyon tutarını/kalemlerini gerçekten değiştirmeniz gerekiyorsa tables/update-orders · packets/update-orders ve update-payments uçlarını kullanın — onlar recompute + paid ≤ total doğrulamasından geçer.

Katman 2 — key namespace sahipliği (GÜVENLİK)

Bazı namespace'ler sahiplenilmiştir; onları yalnız o alanın yetkilisi yazabilir:

NamespaceGereken yetkiAnlamı
tse.*hook scope'u + capability:fiscal.de:provideMali blok (KassenSichV / TSE)
diğer (loyalty.*, kampanya…)hook scope'u yeterliSerbest gösterim öğesi
Neden: aksi halde herhangi bir eklenti tse.qr döndürüp fişe sahte mali blok bastırabilirdi. Yetkisiz eklentinin sahiplenilmiş key'i sessizce düşürülür (dizide yer almaz) — hata dönmez, bu yüzden yetkinizi kurulumda doğrulayın.
Yetki nasıl alınır: manifest'te provides: [{ capability: "fiscal.de" }] beyan edersiniz (portal editöründe "Eklentiler-Arası Yetenekler" kartı); türetilmiş capability:fiscal.de:provide scope'u otomatik eklenir — elle scope seçmezsiniz. Aynı scope, fişi imzalamak için platformdan gelen type:"capability" isteğini almanızı da sağlar: Mali Fişleme (fiscal.de). E-fatura/e-arşiv belgesi ayrı bir yetenektir (invoice.issue) — mali cihaz imzasıyla karıştırmayın; invoice.issue sağlayıcısı tse.* yazamaz.

verified işareti

Sahiplenilmiş namespace'te ve yetki doğrulandıysa platform öğeye verified: true ekler:

{ "key":"tse.txNumber", "type":"text", "label":"Beleg-Nr", "value":"366", "verified":true }
  • Sahiplenilmemiş/bilinmeyen key'ler bu işareti asla almaz — onlara mali anlam yüklenemez.
  • Fiş şablonu mali bloğu yalnız verified öğelere basar.
  • Eklenti verified'ı kendisi gönderemez; platform üretir (gönderilirse yok sayılır).

Yazım kuralları

  • Yalnız allow'da yazılır. deny dönerseniz hiçbir şey yazılmaz — ödeme eşlenemediği için deny döndüyseniz fiş de kesilmemiştir, o key'lerin belgeye girmemesi gerekir. pending'de karar henüz yoktur.
  • Değiştirilemezlik: bir key bir kez yazıldıysa üzerine yazılmaz. Aynı key'i tekrar göndermek sessizce yok sayılır (platformda frozen olarak loglanır). Düzeltme gerekiyorsa fiscal doğru yol iptal/düzeltme belgesidir — yeni bir key ile gönderin.
  • Doküman yoksa yazılmaz: adisyon o arada kapanmış/silinmişse yazım atlanır, gate kararınız etkilenmez.
  • Fail-safe: yazım hatası gate kararını bozmaz. allow dediyseniz kapanış devam eder.

Aynı adisyona birden fazla eklenti yazarsa

Kapanış gate'i tenant-genel fan-out yapar (packet.close tüm kayıtlı eklentilere paralel sorulur), bu yüzden eşzamanlı yazım normaldir:

DurumSonuç
Farklı key'ler (TSE eklentisi tse.*, sadakat eklentisi loyalty.*)İkisi de yazılır, dizi birleşir
Aynı keyİlk yazan kazanır; ikincinin değeri yok sayılır (değiştirilemezlik)

Yani başka bir eklentinin varlığı sizin öğelerinizi ezmez; siz de onunkini ezemezsiniz. 10 eşzamanlı yazımda kayıp gözlenmedi.

Sınırlar

SınırDeğer
Dizi öğe sayısı30 (adisyon başına toplam)
key uzunluğu64
value uzunluğu2000
label uzunluğu64
typetext | qr
tse.qr için özel not: TSE QR verisi ölçümde 341–363 karakter. Sınır bilinçli olarak yüksek tutuldu; 255 karakterlik bir alan bu veriyi taşırdı ve kırpılan QR doğrulanamaz hale gelirdi. Platform uzun değeri kırpmaz — reddeder: bozuk QR üretmektense öğeyi düşürmeyi tercih eder.

Geliştiricinin bilmesi gerekenler

  1. Geri okuma ucu yok. receiptExtras şu an tables/get / packets/get yanıtlarında dönmez. Yazdığınız belge verisini kendi tarafınızda saklayın. Yeniden basım/denetim sorgusu bu mekanizmanın dışındadır: POS bilgisiyle (kasa, belge no, iş günü) sizden çekilir — platform tarafında ek izin gerekmez.
  2. Yalnız kapanış gate'lerinde anlamlıdır (table.close, packet.close). Kapanış olmayan bir hook'ta gönderirseniz fişle ilişkilendirilecek bir belge yoktur.
  3. Fişe basma frontend'in işidir. Platform veriyi güvenli saklar; şablon tse.qr varsa QR basar, tse.status uyarı durumundaysa uyarı gösterir. Öğe sırası fişteki sırayı garanti etmezlabel göndererek anlamı öğenin kendisinde taşıyın.
  4. Timeout bütçesi gate isteğindeki timeoutMs'tir (manifest'ten; table.close varsayılanı 10 sn, paket gate'lerinde 5 sn). Mali belge kesimi bu süreye sığmıyorsa failMode politikanızı gözden geçirin; süre aşımında yanıtınız değerlendirilmez.
  5. Kapatma yetkisi yokallow dönmek kapanışa izin vermektir, kapanışı sizin yapmanız değil.

Örnek — TSE mali bloğu

Gate isteği → allow + receiptExtras → deny
// Gate isteği (platform → eklenti)
{ "type":"hook", "event":"table.close", "target":{ "type":"table", "id":"masa-5" }, "timeoutMs":5000 }

// Yanıt (eklenti → platform) — belge kesildi, fişe basılacak alanlar döndü
{ "decision":"allow",
  "receiptExtras":[
    { "key":"tse.qr",               "type":"qr",   "value":"V0;KassenSN;Kassenbeleg-V1;…" },
    { "key":"tse.txNumber",         "type":"text", "label":"Beleg-Nr",   "value":"366" },
    { "key":"tse.signatureCounter", "type":"text", "label":"Sig-Zähler", "value":"774" },
    { "key":"tse.timeStart",        "type":"text", "label":"TSE-Start",  "value":"1785438065" },
    { "key":"tse.status",           "type":"text", "value":"signed" }
  ] }

// Ödeme eşlenemedi → belge KESİLMEDİ → hiçbir key yazılmamalı
{ "decision":"deny", "message":"Ödeme TSE ile eşlenemedi" }