/** * Kassen-Einstellungen der Browser-Kasse und der Kassen-App in der Form des * Drahts `/api/v3` (Nachtrag Stufe 4, §11.7.2): Schluessel und Katalogwerte * englisch. Zwilling von `functions-kasse/kasse-settings-core.js` (Backend, * dort mit Validator und in der inneren, deutschen Form). * * Betriebsweit (`business`, am Konto) und je Geraet (`device`). Die * Standardwerte stehen hier UND im Backend; `fixtures/pos-settings-defaults.json` * ist aus dem Vertrags-Export abgeleitet (Antwort fuer ein Konto ohne * gespeicherte Einstellungen) und haelt beide deckungsgleich. Die innere Form * derselben Werte liegt unter `fixtures/stored/`. Trinkgeld ist bewusst AUS, * bis die Buchung geklaert ist (Spec kachel-kasse § 9). */ import { type PosVoucherSettings } from './gutschein.js'; export declare const THEME: readonly ["clear", "warm", "night", "contrast"]; export type PosTheme = typeof THEME[number]; export declare const FONT_SIZE: readonly ["S", "M", "L", "XL"]; export type PosFontSize = typeof FONT_SIZE[number]; export declare const WATERMARK: readonly ["off", "login", "everywhere"]; export type PosWatermark = typeof WATERMARK[number]; export declare const QUANTITY: readonly ["off", "x", "kg"]; export type PosQuantity = typeof QUANTITY[number]; export declare const TIP_MODE: readonly ["amount", "total", "both"]; export type PosTipMode = typeof TIP_MODE[number]; export declare const CHECKOUT_MODE: readonly ["page", "panel"]; export type PosCheckoutMode = typeof CHECKOUT_MODE[number]; /** Kartenanbieter: Karte gibt es erst mit eingerichtetem Anbieter; 'external' = eigenes Terminal ohne Anbindung. */ export declare const CARD_PROVIDER: readonly ["none", "external", "gptom", "hobex", "mypos", "stripe"]; export type PosCardProvider = typeof CARD_PROVIDER[number]; export declare const RECEIPT_OUTPUT: readonly ["qr", "print", "email", "sms", "ask"]; export type PosReceiptOutput = typeof RECEIPT_OUTPUT[number]; export declare const LAYOUT: readonly ["right", "left", "fullscreen"]; export type PosLayout = typeof LAYOUT[number]; export declare const CATEGORY_POSITION: readonly ["top", "left"]; export type PosCategoryPosition = typeof CATEGORY_POSITION[number]; export declare const TILE_HEIGHT: readonly ["S", "M", "L"]; export type PosTileHeight = typeof TILE_HEIGHT[number]; /** * `sdp` = Netzwerk ueber Epson Server Direct Print (der Drucker holt Jobs vom Backend, jeder Browser druckt). * `network` = Epson direkt per IP (ePOS). `connect` = Kasseneck Connect (lokaler * Agent auf dem Kassen-Rechner druckt fuer die Browser-Kasse). */ export declare const PRINTER_TYPE: readonly ["sdp", "network", "bluetooth", "usb", "connect"]; export type PosPrinterType = typeof PRINTER_TYPE[number]; /** Terminal-Ansprache: direkt per IP oder ueber Kasseneck Connect (Agent leitet weiter). */ export declare const TERMINAL_VIA: readonly ["direct", "connect"]; export type PosTerminalVia = typeof TERMINAL_VIA[number]; /** Art des Kartenterminals an dieser Kasse: keines oder Hobex HPS (JSON-REST am Geraet). */ export declare const TERMINAL_TYPE: readonly ["none", "hps"]; export type PosTerminalType = typeof TERMINAL_TYPE[number]; export declare const PAPER_SIZE: readonly ["mm58", "mm80"]; export type PosPaperSize = typeof PAPER_SIZE[number]; export declare const CODE_PAGE: readonly ["CP1252", "CP437"]; export type PosCodePage = typeof CODE_PAGE[number]; export declare const CUT: readonly ["partial", "full", "none"]; export type PosCut = typeof CUT[number]; export declare const DRAWER_AUTO_OPEN: readonly ["cash", "always", "never"]; export type PosDrawerAutoOpen = typeof DRAWER_AUTO_OPEN[number]; /** * Mit welchem Befehl der Signatur-QR auf den Bon kommt. * * `raster` = der QR wird als Bild gerastert (GS v 0) und geht darum durch jeden * Drucker, der Bilder kann. `escpos` = der native QR-Befehl (GS ( k): schaerfer * und schneller, aber aeltere Geraete drucken dann gar keinen QR oder * Zeichensalat. * * `auto` ist die Vorgabe und heisst **unbestimmt**: an diesem Geraet hat noch * niemand am Papier entschieden. Jede Kasse bleibt dann bei ihrer bisherigen * Praxis, die Browser-Kasse beim ESC/POS-Befehl, die App beim Rasterbild. * Eine harte Vorgabe waere hier eine stille Umstellung des Altbestands * gewesen: jedes Geraet, das nie durch den Drucker-Wizard lief, druckte * ploetzlich anders, und ueber BLE kostet ein Rasterbild mehrere Sekunden je * Bon. Nur ein ausdruecklich gesetzter Wert aendert etwas. * * **Eine Geraete-Einstellung, keine des Betriebs:** derselbe Bon kommt an einer * Kasse sauber heraus und an der Nebenkasse nicht. Und sie ist nicht * kosmetisch: nach § 132a BAO ist der QR Teil des Belegs; wer den falschen * Modus stehen laesst, erteilt Belege ohne lesbare Signatur. */ export declare const QR_MODE: readonly ["auto", "raster", "escpos"]; export type PosQrMode = typeof QR_MODE[number]; /** Groesse des Kuerzel-Logos in der Kopfzeile der Kasse. */ export declare const LOGO_SIZE: readonly ["S", "M", "L"]; export type PosLogoSize = typeof LOGO_SIZE[number]; /** Schriftgroesse in den Chef-Einstellungen, getrennt von der Schrift der Kasse. */ export declare const SETTINGS_FONT_SIZE: readonly ["S", "M", "L"]; export type PosSettingsFontSize = typeof SETTINGS_FONT_SIZE[number]; /** Kachel-Optik: farbiger Streifen am Rand oder ganz gefuellte Kachel. */ export declare const TILE_STYLE: readonly ["stripe", "full"]; export type PosTileStyle = typeof TILE_STYLE[number]; /** Automatisches Abmelden nach Minuten Ruhe; 0 = nie. */ export declare const AUTO_LOGOUT_MINUTES: readonly [0, 1, 5, 15, 30]; export type PosAutoLogoutMinutes = typeof AUTO_LOGOUT_MINUTES[number]; /** Rabatt am Beleg erlaubt. */ export declare const DISCOUNT: readonly ["off", "on"]; export type PosDiscount = typeof DISCOUNT[number]; /** Seite des Wasserzeichens; ALT, abgeloest von watermarkX. */ export declare const WATERMARK_SIDE: readonly ["left", "center", "right"]; export type PosWatermarkSide = typeof WATERMARK_SIDE[number]; /** Deckkraft des Wasserzeichens in Prozent, bewusst Stufen, kein Schieberegler. */ export declare const WATERMARK_STRENGTH: readonly [3, 6, 10, 16]; export type PosWatermarkStrength = typeof WATERMARK_STRENGTH[number]; /** Groesse des Bild-Logos am Beleg. */ export declare const LOGO_SCALE: readonly ["S", "M", "L", "XL"]; export type PosLogoScale = typeof LOGO_SCALE[number]; /** Groesse des Wasserzeichens, getrennt vom Beleg-Logo. */ export declare const WATERMARK_SCALE: readonly ["S", "M", "L", "XL"]; export type PosWatermarkScale = typeof WATERMARK_SCALE[number]; /** Wie lange die Fertig-Seite stehen bleibt, in Sekunden; 0 = bis zum Tippen. */ export declare const DONE_SCREEN_SECONDS: readonly [0, 3, 5, 10, 15, 30, 60]; export type PosDoneScreenSeconds = typeof DONE_SCREEN_SECONDS[number]; /** Schalter-Landkarte: Steuersaetze / Trinkgeldstufen (Schluessel = Wert als Text, z. B. `'4.9'`). */ export type PosToggleMap = Record; /** * Ein Feld mit Wertemenge, offen fuer Werte, die dieses Paket (noch) nicht * kennt. Kommt vom Server ein neuer Wert (etwa `theme: 'sepia'`), bleibt er im * Modell stehen und geht bei einem Teil-Schreiben nie verloren (der Server * mischt); [unknownPosSettingValues] zeigt, welche Felder das betrifft. */ export type PosOpen = T | (T extends string ? (string & {}) : (number & {})); export interface PosBusinessSettings { logoText: string; logoEnabled: boolean; logoSize: PosOpen; watermark: PosOpen; color: string; theme: PosOpen; fontSize: PosOpen; settingsFontSize: PosOpen; tileStyle: PosOpen; clock: boolean; lockScreen: boolean; /** Fotos der Mitarbeiter am Anmeldebildschirm zeigen. */ staffPhotos: boolean; autoLogoutMinutes: PosOpen; logoutAfterSale: boolean; /** Schnelles Entsperren mit gemerkter PIN (lokal, Server-Login laeuft nach); aus = streng, jeder Login wartet. */ fastLogin: boolean; showPrices: boolean; showVat: boolean; emoji: boolean; categoryColors: boolean; customAmountAllowed: boolean; /** * Steuersaetze an der Kasse. Unter `/v3` **immer die ganze Karte senden** * (Nachtrag §11.7.2): das Backend verlangt mindestens einen Satz an und * liest vor dem Pruefen nicht nach. */ vatRates: PosToggleMap; quantity: PosOpen; note: boolean; search: boolean; discount: PosOpen; /** Bild-Logo (Download-URL aus dem Kasse-Upload); '' = Kuerzel verwenden. */ logoImage: string; /** Seite des Wasserzeichens; ALT: abgeloest von watermarkX, bleibt fuers Mischen alter Staende. */ watermarkSide: PosOpen; /** Horizontale Lage der Wasserzeichen-MITTE in Prozent (-25 bis 125, darf ueber den Rand hinaus). */ watermarkX: number; /** Vertikale Lage der Wasserzeichen-Mitte in Prozent (-25 bis 125). */ watermarkY: number; /** Deckkraft des Wasserzeichens in Prozent, bewusst Stufen, kein Schieberegler. */ watermarkStrength: PosOpen; /** Groesse des Bild-Logos am BELEG (Ansicht, PDF, Kopfzeile). */ logoScale: PosOpen; /** Groesse des Wasserzeichens, getrennt vom Beleg-Logo. */ watermarkScale: PosOpen; payCash: boolean; payCard: boolean; cardProvider: PosOpen; tip: boolean; tipMode: PosOpen; tipSteps: PosToggleMap; /** Trinkgeld-Feinheit (App); kein Leser in der Web-Kasse, der Name ist Vertrag. */ tipSplit: boolean; /** Rueckgeld-Rechner. */ change: boolean; /** „Bar passend": schliesst den Betrag ohne Eintippen bar ab. */ exactCash: boolean; checkoutMode: PosOpen; /** Getrennt zahlen: dritter Knopf neben Bar und Karte, ein Beleg mit mehreren Zahlungen. */ paySplit: boolean; /** Trinkgeld-Chips in Prozent (eine Nachkommastelle, max 5, eindeutig, Reihenfolge des Chefs). */ tipChips: number[]; /** Rabatt-Chips in Prozent, dieselben Regeln wie tipChips, vom Chef einstellbar. */ discountChips: number[]; receiptOutput: PosOpen; doneScreenSeconds: PosOpen; /** Glas-Optik: Kacheln und Korb leicht durchscheinend (Wasserzeichen schimmert). */ glass: boolean; /** Hilfetexte in den Chef-Einstellungen anzeigen. */ hints: boolean; /** * Bar-Trinkgeld behaelt der Mitarbeiter gleich: Vorbelegung des Schalters * „gleich behalten“ beim Kassieren (je Verkauf aenderbar). Optional: der * Server sendet das Feld nur, wenn es gespeichert ist; fehlt es, gilt aus. * Lesen ueber [posTipKeptByDefault]. Siehe [POS_BUSINESS_OPTIONAL_FIELDS]. */ tipKeptByDefault?: boolean; } /** Aktionen der Kasse, die eine Taste bekommen koennen (Schluessel von `device.shortcuts`). */ export declare const POS_SHORTCUT_ACTIONS: readonly ["checkout", "complete", "cancel", "customAmount", "cash", "card", "exactAmount", "receipts", "undoLast", "settings", "logout", "tip", "fullscreen", "clearTendered", "clearCart", "splitPayment", "shiftStatus", "openDrawer", "voucherPayout"]; export type PosShortcutAction = typeof POS_SHORTCUT_ACTIONS[number]; /** Tastenkarte: Aktion -> Tasten (`Mod+F`, `Enter`, `Escape`, `F5` ...; `Mod` = ⌘ auf dem Mac, Strg sonst). */ export type PosShortcutMap = Record; export declare const POS_SHORTCUT_DEFAULTS: Readonly; /** * Aktionen, die sich eine Taste teilen duerfen (Backend `TASTEN_PAARE`): sie * leben in verschiedenen Momenten, der Verteiler laesst die nicht zustaendige * durchfallen. Jede andere Doppelbelegung weist der Server ab, und dieses * Paket schon vor dem Senden. */ export declare const POS_SHORTCUT_SHARED_PAIRS: readonly (readonly [PosShortcutAction, PosShortcutAction])[]; /** * Die erste Doppelbelegung einer Tastenkarte: `{ action, key, heldBy }` oder * `null`. Geprueft wird die ganze Karte, so wie der Server sie nach dem * Speichern haelt (er selbst prueft nur die gesendeten Eintraege). */ export declare function posShortcutConflict(shortcuts: Readonly>): { action: string; key: string; heldBy: string; } | null; export interface PosDeviceSettings { layout: PosOpen; categoryPosition: PosOpen; extraColumns: number; tileHeight: PosOpen; touch: boolean; /** Tastenbelegung dieses Geraets (Vorgabe POS_SHORTCUT_DEFAULTS, je Aktion mischbar). */ shortcuts: PosShortcutMap; printerEnabled: boolean; printerType: PosOpen; printerIp: string; printerPort: number; printerBluetoothId: string; /** Klartextname des gemerkten Druckers; sonst stuende dort eine nackte Bluetooth-Adresse. */ printerName: string; /** Kennung des Netzwerk-Druckers (Server Direct Print) aus `listMyPrinters`; '' = keiner gewaehlt. */ printerId: string; /** ePOS Device-ID bei `printerType 'network'` (Epson direkt per IP), Vorgabe `local_printer`. */ printerDeviceId: string; /** Kennung des Druckers im lokalen Kasseneck-Connect-Agenten, bei `printerType 'connect'`. */ connectPrinterId: string; paperSize: PosOpen; codePage: PosOpen; cut: PosOpen; /** Befehl fuer den Signatur-QR auf dem Bon; 'auto' = unbestimmt, der Drucker-Wizard probiert beide aus. */ qrMode: PosOpen; drawerEnabled: boolean; drawerAutoOpen: PosOpen; /** * Lade dieses Geraets (Schichtbetrieb). Optional: der Server sendet das * Feld nur, wenn eine Lade zugeordnet ist; fehlt es, gilt die Hauptlade der * Kasse. Beim Schreiben entfernt `null` die Zuordnung. Siehe * [POS_DEVICE_OPTIONAL_FIELDS]. */ drawerId?: string | null; terminalIp: string; terminalPort: number; terminalVia: PosOpen; /** Art des Terminals ('none' = Kartenzahlung ohne Terminal-Anbindung gesperrt, sofern payCard an). */ terminalType: PosOpen; /** Tastenmarken (die kleinen Kuerzel an den Knoepfen) anzeigen. */ shortcutHints: boolean; /** Terminal-ID aus dem Hobex-Vertrag (ohne fuehrende Null); noetig fuer Diagnose und Zahlung. */ terminalTid: string; } export interface PosSettings { business: PosBusinessSettings; device: PosDeviceSettings; /** Gutschein-Verkauf der Kasse (Block `vouchers`); ohne Block ist Verkaufen aus. */ vouchers: PosVoucherSettings; } export declare const POS_BUSINESS_DEFAULTS: Readonly; export declare const POS_DEVICE_DEFAULTS: Readonly; /** * Optionale Geraete-Einstellungen: ohne Standardwert, der Server sendet sie * nur, wenn sie gesetzt sind (Backend `GERAET_OPTIONAL`). Sie fehlen darum in * [POS_DEVICE_DEFAULTS]; [mergePosSettings] uebernimmt sie, wenn sie als * Kennung kommen, und der Schreibweg nimmt sie als Kennung oder `null` * (Zuordnung entfernen). */ export declare const POS_DEVICE_OPTIONAL_FIELDS: readonly ["drawerId"]; /** Gilt dieser Wert fuer ein optionales Feld? Lesen: nur eine Kennung; Schreiben: auch `null`. */ export declare function _optionalerWert(wert: unknown, schreiben: boolean): boolean; /** * Optionale Betriebs-Einstellungen (Schalter): ohne Standardwert, der Server * sendet sie nur, wenn sie gespeichert sind (Backend `BETRIEB_OPTIONAL`). * [mergePosSettings] uebernimmt sie nur als Wahrheitswert; der Schreibweg * nimmt nur `true`/`false`. */ export declare const POS_BUSINESS_OPTIONAL_FIELDS: readonly ["tipKeptByDefault"]; /** Bar-Trinkgeld „gleich behalten“ vorbelegt? Fehlt die Einstellung, gilt aus. */ export declare function posTipKeptByDefault(business: Readonly> | null | undefined): boolean; /** * Die Wertemenge je Feld, soweit das Feld eine hat: dagegen prueft der * Schreibweg vor dem Senden (ein deutscher Wert wie `'nacht'` geht so gar * nicht erst hinaus). Die Wahrheit ueber Gueltigkeit hat weiter das Backend. */ export declare const POS_BUSINESS_VALUES: Readonly>>; /** Wie [POS_BUSINESS_VALUES] fuer die Geraete-Einstellungen. */ export declare const POS_DEVICE_VALUES: Readonly>>; /** Ein Wert der inneren Form 0.x fuer dieses Feld? (paketintern, fuer die Meldung der Vorab-Pruefung) */ export declare function _istAltwert0x(feld: string, wert: unknown): boolean; /** Nur fuer den Test: die beiden Tabellen der inneren Form. */ export declare const _ALTFORM_0X: Readonly<{ werte: Readonly>; aktionen: string[]; }>; /** * Standard + stored. Landkarten (`vatRates`, `tipSteps`, `shortcuts`) * werden je Schluessel gemischt, damit neue Saetze beim Altbestand ankommen; * Schluessel, die der Standard nicht fuehrt, bleiben draussen, ausser einer * optionalen Geraete-Einstellung ([POS_DEVICE_OPTIONAL_FIELDS]) mit gueltiger * Kennung und einem optionalen Betriebs-Schalter * ([POS_BUSINESS_OPTIONAL_FIELDS]) als Wahrheitswert. * * **Immer** (unabhaengig davon, welches Standard-Objekt uebergeben wird, auch * eine Kopie oder das einer zweiten Paketkopie) faellt ein Wert der inneren * Form 0.x auf den Standard zurueck (`layout: 'rechts'`, `terminalVia: * 'direkt'`), und deutsche Tasten-Aktionen (`kassieren`) kommen nicht in die * Tastenkarte. Ein unbekannter **englischer** Wert (`theme: 'sepia'`) bleibt * dagegen stehen: er kann ein neuer Wert des Servers sein. */ export declare function mergePosSettings(standard: Readonly, stored: Partial | null | undefined): T; /** * Einen gespeicherten oder zwischengespeicherten Stand `{business, device}` * lesen: gemischt mit den Standardwerten, ohne Werte und Tasten-Aktionen der * inneren Form 0.x (siehe [mergePosSettings]). Der Weg fuer jeden Stand, den * ein Verbraucher selbst abgelegt hat; ein Stand in der inneren Form ergibt * die Standardwerte, nie einen deutschen Wert und nie einen Absturz. */ export declare function sanitizePosSettings(stored: unknown): PosSettings; /** * Die Felder, deren Wert dieses Paket nicht kennt (neuer Wert des Servers), * als Pfade (`business.theme`, `device.printerType`). Die Oberflaeche kann sie * als „vom Server, hier nicht einstellbar" zeigen; sie bleiben erhalten, solange * nur geaenderte Felder geschrieben werden ([posSettingsChanges]). */ export declare function unknownPosSettingValues(settings: PosSettings): string[]; /** * Was sich zwischen zwei Staenden eines Teils geaendert hat, als Nutzlast fuer * `setMyPosSettings` bzw. `setMyRegisterDeviceSettings`: **nur geaenderte * Felder** (der Server mischt, ein nicht geaenderter, hier unbekannter Wert * geht so nie verloren). `vatRates` geht bei einer Aenderung als ganze Karte * (Nachtrag §11.7.2), `shortcuts` ebenfalls ganz, aber nur mit den Aktionen, * die dieses Paket kennt: so sieht die Doppelbelegungspruefung des Servers die * ganze Belegung, und eine unbekannte Aktion bleibt per Mischen am Server * stehen. `tipSteps` geht nur mit den geaenderten Eintraegen. */ export declare function posSettingsChanges(before: Readonly, after: Readonly): Partial;