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.
GET {RESTOMENUM_BASE}/plugin-api/tables/get?id=<encodeURIComponent(target.id)>
Authorization: Bearer <apiKey> // kurulumdaki (OAuth exchange) install API key{RESTOMENUM_BASE}): ortama göre — Sandbox https://sandbox.plugins.restomenum.app, Production https://plugins.restomenum.app (tüm liste: API Uçları).Authorization: Bearer <apiKey> — kurulumda OAuth token exchange'te aldığın apiKey.orders:read zorunlu (yoksa plugin.scope.denied).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.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
}}| Alan | Açı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 / location | Masanın görünen adı / alanı / konumu. |
| total / paid / totalDiscount | Hesap 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. |
| customer | Varsa müşteri (PII; customers:read + consent ile). Dine-in'de genelde yok. |
| type | Tüketim biçimi — masa hesabında daima "dine_in" (türetilir; tables/create bu alanı almaz). |
| currency / amountExponent | Para 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. |
{
"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
}]
}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.Temiz satır — iç alanlar (ham product objesi, log, requestId, storages…) gönderilmez; yalnız ihtiyacın olanlar:
| Alan | Açıklama |
|---|---|
| id | Satır id (referans) — lineId ile aynı değer (yazma/okuma simetrisi). |
| lineId | Kalıcı satır kimliği; eski/panel satırlarında null. |
| metadata | Yazmada 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ı. |
| quantity | Adet. ⏳ 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 }). |
| options | Seçili seçenekler — nesne dizisi { id, title, price } (eskiden düz ad dizisiydi). price katalogtan gelir ve lineTotalDecimal'a platformca dahildir. |
| extraDecimal / discountDecimal | Ekstra / 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. |
| note | Satır notu. |
| lineTotalDecimal | Satır toplamı (Restomenum hesaplar) — ondalık. ⚠️ Eski adı lineTotal. |
| vatRate | Satırın KDV oranı (%) — üründen dondurulur. |
| amounts | Tutar 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[], 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.
// 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
}| Alan | Tip | Zorunlu | Açıklama |
|---|---|---|---|
| methodId | string | 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). |
| title | string | ✓ | Yöntemin tenant tanımındaki başlığı (örn. "nakit"). Gösterim içindir. |
| amount | number | ✓ | Satır tutarı. Tüm satırların toplamı paid'e eşittir (indirim satırları dahil). |
| cash | boolean | ✓ | 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. |
| cashDeclared | boolean | ✓ | 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ı. |
| isDiscount | boolean | ✓ | true → satır bir indirimdir, tahsilat değildir. Satır listeden düşürülmez; totalDiscount bu satırlardan türetilir. |
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.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 + 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.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ı.)sum(amount) === paid korunur. Mali toplamda isDiscount:true satırlarını tahsilat gibi sayma; ama listeden atarsan toplam paid'i tutmaz.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.| Durum | Yanıt |
|---|---|
| Masa yok (veya çift-decode'lu id) | { success:false, message:"plugin.tables.notFound" } |
| Scope yok | { success:false, message:"plugin.scope.denied" } |
// 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