Masa Detayı — GET /plugin-api/tables/get ✓ Canlı

table.close gate'i yalnızca bir referans taşır (target:{type:'table', id:'…'}); masanın DOLU içeriğini (ürünler, tutar, ödeme kırılımı, müşteri) bu uçtan, o id ile çekersiniz. Satır desenleri (orders[], payments[]) packets/get ile aynıdır; kimlik/başlık alanları masaya özeldir (tableId/tableName/desing — packetId değil).

← API Uçları · ortak kurallar (base, auth, hata zarfı) orada.

İstek

GET {RESTOMENUM_BASE}/plugin-api/tables/get?id=<encodeURIComponent(target.id)>
Authorization: Bearer <apiKey>     // kurulumdaki (OAuth exchange) install API key
  • Base ({RESTOMENUM_BASE}): ortama göre — Sandbox https://sandbox.plugins.restomenum.app, Production https://plugins.restomenum.app (tüm liste: API Uçları).
  • Auth: Authorization: Bearer <apiKey> — kurulumda OAuth token exchange'te aldığın apiKey.
  • Scope: orders:read zorunlu (yoksa plugin.scope.denied).
URL-encode zorunlu: target.id URL-encoded olabilir (örn. bah%C3%A7e1 — Türkçe ç yüzünden). Query'de mutlaka encodeURIComponent(target.id) kullan; yoksa çift-decode olur → plugin.tables.notFound.

Yanıt

Envelope ({ success, data }) ve temiz orders[] satır deseni packets/get ile aynıdır; ancak kimlik/başlık alanları MASAYA özeldir (tableId/tableName/desing/location/personCount — packetId/entegrasyon değil). Canlı örnek (gerçek masa Bahçe1):

{ "success": true, "data": {
  "tableId": "bah%C3%A7e1",      // doküman id (target.id ile aynı)
  "tableName": "Bahçe1",         // görünen ad
  "docNo": 7,
  "desing": "Bahçe",             // masa/alan
  "location": "Bahçe1",
  "personCount": 0,
  "total": 360.5,
  "paid": 50,
  "totalDiscount": 0,
  "orders": [
    { "id": "bah%C3%A7e1-7c08", "title": "HYPATİA KAHVALTI", "quantity": 1, "options": [], "extraDecimal": 0, "discountDecimal": 0,   "note": "", "lineTotalDecimal": 160 },
    { "id": "bah%C3%A7e1-9624", "title": "KÖRİ SOSLU TAVUK",  "quantity": 1, "options": [], "extraDecimal": 0, "discountDecimal": 6.5, "note": "", "lineTotalDecimal": 58.5 }
  ],
  "payments": [ { "methodId": …, "title": …, "amount": …, "cash": …, "isDiscount": … } ]
  // ↑ ödeme kırılımı — packets/get ile BİREBİR aynı satır (şema aşağıda); paid bu satırların toplamıdır
  // "customer": { … }   // dine-in'de genelde yok; varsa customers:read + consent ile
}}
AlanAçıklama
tableId⚠️ Adres/slug — kimlik DEĞİL (target.id ile aynı; URL-encoded olabilir). Satış boyunca değişebilir (geri açmada masa-904 → masa-904*; kapanış olayında ölçümde kapanış kaydının kimliği görüldü) → anahtar olarak kullanma. Satışın kimliği uuid'dir; anahtarlama kuralı.
tableName / desing / locationMasanın görünen adı / alanı / konumu.
total / paid / totalDiscountHesap toplamı / ödenen / indirim toplamı.
orders[]Sipariş satırları (aşağıdaki şema).
payments[]Ödeme kırılımı — { methodId, title, amount, cash, isDiscount } (aşağıdaki şema). packets/get ile birebir aynı; paid bu satırların toplamıdır.
customerVarsa müşteri (PII; customers:read + consent ile). Dine-in'de genelde yok.
typeTüketim biçimi — masa hesabında daima "dine_in" (türetilir; tables/create bu alanı almaz).
currency / amountExponentPara birimi (ISO-4217) + amounts.* için ondalık basamak (TRY → 2). ⚠️ Üs yalnız orders[].amounts içindir — total/paid/lineTotalDecimal ondalıktır. Tenant'ın para birimi çözülemezse alanlar hiç gelmez.
Satır kimliği, korelasyon alanı ve satış tipi
{
  "type": "dine_in",                  // MASA hesabında DAİMA "dine_in" (türetilir; istekte gönderilmez)
  "orders": [{
    "id": "bah%C3%A7e1-7c08",
    "lineId": "qr-9f2c",              // KALICI satır kimliği; eski/panel satırlarında null
    "metadata": [                     // DİZİ; hiç yazılmadıysa null
      { "key": "seat", "value": "2", "by": "qrsiparis" },              // by = YAZAR (platform damgalar)
      { "key": "tseRef", "value": "TSE-9911", "by": "fiskaly" }        // başka eklentinin öğesi
    ]
  }],
  "payments": [{
    "lineId": "pay-7c31",             // KALICI satır kimliği (yoksa null) — methodId ile KARIŞTIRMA
    "methodId": "m-cash",             // ödeme YÖNTEMİ id'si
    "metadata": [ { "key": "terminal", "value": "kiosk-1", "by": "qrsiparis" } ]   // yoksa null
  }]
}
Yeni alanlar. Satır düzeyinde lineId + metadata, satış düzeyinde type. Satır alanları eski kayıtlarda null döner (kimlik uydurulmaz); payments[].id'ye fallback yapılmaz. Aynı alanlar packets/get ve table.close gate gövdesinde de gelir — hepsi aynı modelden üretilir.

orders[] satırı

Temiz satır — iç alanlar (ham product objesi, log, requestId, storages…) gönderilmez; yalnız ihtiyacın olanlar:

AlanAçıklama
idSatır id (referans) — lineId ile aynı değer (yazma/okuma simetrisi).
lineIdKalıcı satır kimliği; eski/panel satırlarında null.
metadataYazmada iliştirilen opak korelasyon alanı — yazar damgalı { key, value, by } dizisi (kendi öğelerini by ile ayıkla); hiç yazılmadıysa null. orders:read yeterlidir, PII rızası gerekmez.
titleÜrün adı.
quantityAdet. ⏳ Tip garantisi: her zaman sonlu bir sayı; string ayrıştırılır (virgül ondalık ayırıcı toleranslı), boş/çözülemeyen değer ve eksik alan 1'e düşer (alan payload'dan düşmez), açık 0 korunur. Fallback 1'dir çünkü satırın lineTotalDecimal'ı eksik adedi 1 kabul ederek hesaplanır — 0 deseydik gövde kendini yalanlardı ({ quantity: 0, lineTotalDecimal: 100 }).
optionsSeçili seçenekler — nesne dizisi { id, title, price } (eskiden düz ad dizisiydi). price katalogtan gelir ve lineTotalDecimal'a platformca dahildir.
extraDecimal / discountDecimalEkstra / satır indirimi. ⚠️ Kırıcı: eski adları extra/discount'tu — aynı ad iki para ölçeğinde yaşamasın diye sonek eklendi. ⏳ Tip garantisi: her zaman sonlu bir sayı gelir — string değerler ayrıştırılır (virgül ondalık ayırıcı toleranslı), boş/çözülemeyen değer ve eksik alan 0'a düşer (payload'dan düşmez). Bu üç alan (quantity dahil) eskiden dokümandan ham geçiyordu — lineTotalDecimal/vatRate normalize edilirken. Yuvarlama yapılmaz: quantity para değildir, kilo bazlı satır ikiden fazla ondalık taşıyabilir. Ölçüm: 4 üretim hesabı · 1196 satır → tamamı zaten sayıydı; bu bir veri düzeltmesi değil, sözleşme garantisi.
noteSatır notu.
lineTotalDecimalSatır toplamı (Restomenum hesaplar) — ondalık. ⚠️ Eski adı lineTotal.
vatRateSatırın KDV oranı (%) — üründen dondurulur.
amountsTutar kırılımı — tamsayı minor unit: { base, options, extra, discount, timer, gross, net, vat, perVat? }. gross satır toplamının tek kaynağıdır; garanti: base + options + extra − discount + timer === gross ve net + vat === gross. Satırın verisi bozuksa yalnız o satırda düşer.

payments[] — ödeme kırılımı

payments[], masanın ödeme satırlarını taşır ve orders:read ile gelir. Aynı satır şekli packets/get, tables/get ve packet.created yüzeylerinde birebir aynıdır. İç alanlar (created = işlemi yapan personel, log, description) gönderilmez.

Satır şeması
// payments[] satırı — allowlist (packets/get · tables/get · packet.created BİREBİR AYNI)
{
  "methodId":   string | null,   // tenant'ın ödeme yöntemi id'si; tanımlı yönteme bağlı değilse null
  "title":      string,          // yöntemin başlığı (tenant tanımı) — gösterim için
  "amount":     number,          // satır tutarı
  "cash":       boolean,         // yöntem NAKİT mi → CASH / NON_CASH ayrımı YALNIZ buradan okunur
  "cashDeclared": boolean,       // cash BEYAN mı, yoksa platformun güvenli varsayımı mı
  "isDiscount": boolean          // true → indirim satırı (tahsilat DEĞİL), satır listede KALIR
}
AlanTipZorunluAçıklama
methodIdstring | null✓Tenant'ın ödeme yöntemi id'si — geçerli id'ler payment-methods/list'ten gelir. Satır tanımlı bir yönteme bağlı değilse null (satırın kendi uuid'si sızdırılmaz).
titlestring✓Yöntemin tenant tanımındaki başlığı (örn. "nakit"). Gösterim içindir.
amountnumber✓Satır tutarı. Tüm satırların toplamı paid'e eşittir (indirim satırları dahil).
cashboolean✓Yöntem nakit mi. Mali CASH/NON_CASH ayrımının tek doğru kaynağı budur; tenant tanımında işaretli değilse false gelir.
cashDeclaredboolean✓cash bir beyan mı, yoksa platformun güvenli varsayımı mı? false → yöntem kaydında nakitlik alanı hiç doğmamış. Mali damgalamada bu ayrım kritiktir — bkz. aşağıdaki uyarı.
isDiscountboolean✓true → satır bir indirimdir, tahsilat değildir. Satır listeden düşürülmez; totalDiscount bu satırlardan türetilir.
Nakit ayrımını cash bayrağından oku — methodId veya title METNİNDEN çıkarma. Id'ler tenant'a özeldir ("29-cash" gibi bir id nakit olmayabilir, "kart" adlı bir yöntem nakit işaretli olabilir). Ayrıntı için payment-methods/list.
cashDeclared:false ise cash bir varsayımdır. Yöntem kaydında nakitlik alanı hiç doğmamıştır (genelde kiracı açılışında oluşan varsayılan yöntemler). Almanya'da ödeme tipi (Bar/Unbar) imzalanan fişin güvence altına alınan verisidir (ZAHLART_TYP): cashDeclared:false görürsen varsayıma dayalı sınıflandırmayı damgalama, kiracıdan beyan iste.
Aynı alan payment-methods/list kataloğunda da var — satırda ayrıca bulunmasının sebebi join'in çalışmaması: ölçümde ödeme satırlarının %39'u kiracı kataloğunda karşılığı olmayan bir methodId taşıyor (teslimat entegrasyonlarının ürettiği sözde-yöntemler). O satırlarda join edecek hedef YOKTUR → nakitlik bilgisini satırdan oku.
Satır kimliği ve korelasyon alanı
// Satır kimliği + korelasyon alanı — aynı satırda döner
{
  "lineId":   string | null,     // KALICI satır kimliği; eski/panel satırlarında null (id'ye FALLBACK YOK)
  "metadata": [ { key, value, by } ] | null   // opak korelasyon DİZİSİ; by = yazar (platform damgalar)
}
lineId ≠ methodId. lineId satırın kalıcı kimliğidir; methodId ödeme yönteminin id'sidir. Panel/yerli akışta veya bu sürümden önce yazılmış satırlarda lineId ve metadata null döner ve yazmadaki payments[].id'ye fallback yapılmaz — o alan yöntem id'si de olabildiği için iki farklı satırı aynı kimlikle gösterirdi. Kimlik uydurmak yerine "bilinmiyor" denir. Kurallar: Satır kimliği & metadata.
⏳ Yeni: cancelPayments[] — iptal edilen tahsilatlar. payments[] ile birebir aynı şekil (yeni bir tip öğrenmene gerek yok). Satır void'i (cancels) yayınlanırken ödeme void'inin yayınlanmaması doğrudan bir asimetriydi: iptal edilmiş bir tahsilat tüketiciye hiç görünmüyor, defterdeki "ödenmiş" tutar POS'takinden sapıyordu. ⚠️ paid aktif ödemelerin toplamıdır — bu liste ona dahil değildir. (Sandbox'ta canlı, production'a dağıtılmadı.)
Toplam tutarlılığı: indirim satırları da listede kaldığı için sum(amount) === paid korunur. Mali toplamda isDiscount:true satırlarını tahsilat gibi sayma; ama listeden atarsan toplam paid'i tutmaz.

PII (customer)

customer alanları webhook ile aynı kuralla kırpılır: customers:read yoksa PII alanları (name, phone, address, email, tckn, vergino) silinir. Dine-in masalarda customer genelde hiç bulunmaz.

Hatalar

DurumYanıt
Masa yok (veya çift-decode'lu id){ success:false, message:"plugin.tables.notFound" }
Scope yok{ success:false, message:"plugin.scope.denied" }

Kullanım (table.close gate ile)

// table.close gate (/api/hook) içinde: gate yalnız target.id taşır → masanın DOLU hesabını çek.
const r = await fetch(`${BASE}/plugin-api/tables/get?id=${encodeURIComponent(hook.target.id)}`, {
  headers: { authorization: 'Bearer ' + apiKey },   // kurulumdaki install API key
}).then((x) => x.json());
const bill = r.data;          // bill.total, bill.orders → faturayı kes