import { VatRate } from '../enums/index.js'; import { type ReturnDisposition } from './cancellation.js'; /** * Belegposition — Zwilling von `KasseneckItem` in * kasseneck_api/lib/models/kasseneck_item.dart. * * `priceCents` ist der Einzelpreis in **Cent** (exakte Integer-Arithmetik, * keine Gleitkomma-Rundungsfehler). Eine Euro-Variante gibt es hier bewusst * nicht — anders als beim Gutschein oder Hobex-Beleg sendet die Nutzlast * (v2-Format) den Preis bereits als ganze Cent. * * `vat` ist beim Lesen entweder der bekannte Steuersatz (Objekt) oder — falls * die Nutzlast einen Satz traegt, den dieses Paket noch nicht kennt — der * rohe `rate`-Wert als Zahl (siehe [readVatRateByRate]). Ein Aufrufer erkennt * den unbekannten Fall am `typeof`: ein Objekt ist bekannt, eine Zahl nicht. * * `quantity` ist beim **Schreiben** eine ganze Menge; TypeScript kennt keinen * Ganzzahltyp, deshalb prueft der Schreibpfad sie zur Laufzeit (siehe * [receiptItemIsValid] und [toReceiptItemPayload]). Beim **Lesen** steht hier, * was in der Nutzlast stand — auch eine gebrochene Menge aus fremder Hand: * lesen tolerant, schreiben streng. `receiptItemTotalCents` liefert dann * folgerichtig einen gebrochenen Cent-Betrag; das ist die Wahrheit des * Belegs, nicht ein Fehler dieses Pakets. */ export interface ReceiptItem { name: string; /** Ganze Menge, > 0 zum Senden (siehe Klassenkommentar). */ quantity: number; vat: VatRate | number; priceCents: number; /** * Trinkgeld-Position (vom Backend aus dem Parameter `tip` erzeugt, siehe * [ReceiptCommonOptions.tip]) oder Rabatt-Position (`distributeDiscount`). * Mitarbeiter-Trinkgeld ist Durchlaeufer (0 %, kein Umsatz), * Inhaber-Trinkgeld (`recipient.owner`) Umsatz. Rabatt-Positionen sind * negative Entgeltminderungen je Steuersatz; die Kennzeichnung steuert nur * die Bon-Darstellung (Summenzeile mit Aufteilung), nie die Beträge. */ kind?: 'tip' | 'discount' | 'voucher' | 'voucher_float'; /** Empfaenger der Trinkgeld-Position; `null` = nicht zugeordnet. */ recipient?: TipRecipient | null; /** Zahlart der Trinkgeld-Position (kann von der des Belegs abweichen). */ paymentMethod?: string; /** * Nur Personal-Trinkgeld: hat der Empfaenger das Geld schon (`true`) oder * behaelt der Betrieb es und schuldet es (`false`)? Fehlt bei Altbelegen. */ receivedImmediately?: boolean; /** * Nur Personal-Trinkgeld bar: die Mitarbeiterin hat es beim Verkauf gleich * eingesteckt („gleich behalten“). Nur ein Merkmal fuer den Kassenstand; * fehlt sonst. */ keptByEmployee?: boolean; /** * Artikel-Verweis (Artikelstamm) — Grundlage der Erloesgruppen-Zuordnung * im Bericht. Optional; Handeingaben haben keinen. */ articleId?: string; /** Nur an Storno-Zeilen mit `articleId`: Index der Position im Original. */ originalIndex?: number; /** Nur an Storno-Zeilen mit `articleId`: wohin die Ware ging (Lager-Kern Stufe 2). */ returnDisposition?: ReturnDisposition; } /** Empfaenger einer Trinkgeld-Position (Kassen-Benutzer, Snapshot des Namens). */ export interface TipRecipient { registerUserId: string; name: string; /** true: Inhaber — das Trinkgeld ist Umsatz mit USt. */ owner?: boolean; } /** Trinkgeld-Position? Die eine Erkennungsstelle — niemand prueft `kind` selbst. */ export declare function isTipItem(item: ReceiptItem | ReceiptItemPayloadRead): boolean; /** Rabatt-Position? Die eine Erkennungsstelle — niemand prueft `kind` selbst. */ export declare function isDiscountItem(item: ReceiptItem | ReceiptItemPayloadRead): boolean; /** * Gutschein-Position (Server, neue Gutscheinform)? `voucher` ist eine * Einloesung oder ein Verkauf mit Umsatzsteuer-Wirkung, siehe * [isVoucherFloatItem] fuer den durchlaufenden Posten. */ export declare function isVoucherItem(item: ReceiptItem | ReceiptItemPayloadRead): boolean; /** Gutschein-Position als durchlaufender Posten (Mehrzweck: Verkauf, Auszahlung)? */ export declare function isVoucherFloatItem(item: ReceiptItem | ReceiptItemPayloadRead): boolean; /** * Nutzlast-Form, die dieses Paket **schreibt** (v2): * `{ name, quantity, unitPriceCents, vatRate }`. */ export interface ReceiptItemPayload { name: string; quantity: number; unitPriceCents: number; vatRate: number; /** Trinkgeld-/Rabatt-/Gutschein-Kennzeichnung, siehe [ReceiptItem.kind]. */ kind?: 'tip' | 'discount' | 'voucher' | 'voucher_float'; recipient?: TipRecipient | null; paymentMethod?: string; receivedImmediately?: boolean; /** Trinkgeld-Position, siehe [ReceiptItem.keptByEmployee]; nur `true`. */ keptByEmployee?: boolean; /** Artikel-Verweis, siehe [ReceiptItem.articleId]. */ articleId?: string; } /** * Nutzlast-Form, die dieses Paket **liest** — v2 und v1 nebeneinander, alles * optional (Zwilling von `KasseneckItem.fromJson`). * * Das ist kein Entgegenkommen, sondern der Normalfall: Das Backend bildet die * v2-Felder am Eingang auf v1 ab und **speichert v1** (`normalizeMoneyInputs` * in functions/index.js — quantity->amount, vatRate->vat, * unitPriceCents->priceOneCents, daraus priceOne). Ein gespeicherter Beleg * traegt v1 also immer, v2 nur dann, wenn der erzeugende Client sie * mitgesendet hat. Wer hier nur v2 liest, bekommt bei Belegen von * Alt-Clients `undefined` in Menge, Steuersatz und Preis — ohne Fehler, aber * mit `NaN` in jeder Summe und mit einem Beleg, der sich nicht mehr * stornieren laesst. */ export interface ReceiptItemPayloadRead { name?: string | null; /** Trinkgeld-Position (Backend), siehe [ReceiptItem.kind]. */ kind?: string | null; recipient?: TipRecipient | null; paymentMethod?: string | null; /** Trinkgeld-Position, siehe [ReceiptItem.receivedImmediately]. */ receivedImmediately?: boolean | null; /** Trinkgeld-Position, siehe [ReceiptItem.keptByEmployee]. */ keptByEmployee?: boolean | null; /** v2: Menge */ quantity?: number | null; /** v2: Einzelpreis in Cent */ unitPriceCents?: number | null; /** v2: Steuersatz */ vatRate?: number | null; /** v1: Menge */ amount?: number | null; /** v1: Einzelpreis in Cent */ priceOneCents?: number | null; /** v1: Einzelpreis in Euro */ priceOne?: number | null; /** v1: Steuersatz */ vat?: number | null; /** Artikel-Verweis, siehe [ReceiptItem.articleId]. */ articleId?: string | null; /** Storno-Zeile mit `articleId`: Index im Original, siehe [ReceiptItem.originalIndex]. */ originalIndex?: number | null; /** Storno-Zeile mit `articleId`: Rueckgabe-Wahl, siehe [ReceiptItem.returnDisposition]. */ returnDisposition?: string | null; } export declare function toReceiptItemPayload(item: ReceiptItem): ReceiptItemPayload; /** * Liest beide Nutzlast-Formen (siehe [ReceiptItemPayloadRead]). Reihenfolge * wie im Dart-Vorbild: v2 vor v1, Cent-Angabe vor Euro-Angabe (exakt vor * gerundet); die Euro-Angabe wird genau einmal auf Cent gerundet. */ export declare function fromReceiptItemPayload(payload: ReceiptItemPayloadRead): ReceiptItem; /** * Zeilensumme in Cent. Bei einer selbst erzeugten Position ist sie exakt: * ganze Menge mal ganze Cent. Bei einem fremd erzeugten Beleg mit gebrochener * Menge ist sie folgerichtig gebrochen — das ist der signierte Betrag, und ihn * zu runden hiesse, einen anderen zu drucken. */ export declare function receiptItemTotalCents(item: ReceiptItem): number; /** * Ist die Position an das Backend sendbar? Zwilling von `KasseneckItem.isValid` * im Flutter-Vorbild: ein Name muss da sein und die Menge positiv **und ganz**. * Der Preis darf negativ sein — genau das ist eine Stornoposition. * * Zur Ganzzahligkeit siehe [pruefeMenge]: im Dart-Vorbild ist `quantity` ein * `int`, hier traegt der Typ das nicht, also muss es die Laufzeit tun. */ export declare function receiptItemIsValid(item: ReceiptItem): boolean; /** * Stornoposition zu dieser Position — Zwilling von `KasseneckItem.negative`: * gleicher Name, gleiche Menge, gleicher Steuersatz, **negierter** Einzelpreis. * Die Menge bleibt positiv; das Vorzeichen sitzt ausschliesslich im Preis. */ export declare function negateReceiptItem(item: ReceiptItem): ReceiptItem;