import type { InternerTransport } from '../client/aufrufe.js'; import { type AfterCountType, type CashLocation, type CashMovementResult, type CloseShiftResult, type Denominations, type DrawerOpeningsResult, type DrawerState, type ManualMovementType, type OpeningReason, type OpenShiftResult, type ShiftReport, type ShiftTipTotals } from './schicht-typen.js'; /** * Schicht, Kassenstand und Lade-Protokoll an der Kasse (Backend * schicht-endpoints.js). Alle sechs Aufrufe gibt es nur ueber den Kassenweg * `/api/v3`; sie laufen mit dem Kassen-Benutzer-Weg (`registerUserAuth`). * * Rechte am Server: `shift` (Schicht oeffnen und schliessen, Bericht), * `cashMove` (Ein- und Auszahlungen), `cashView` (Soll, Ist und Differenz * sehen; ohne dieses Recht wird blind gezaehlt), `drawer` (Lade von Hand * oeffnen). [getMyDrawerState] braucht kein Recht und nennt alle vier. * * **Schreiben mit Idempotenzschluessel:** [openMyShift], * [recordMyCashMovement] und [closeMyShift] verlangen `idempotencyKey`, jeder * Eintrag von [logMyDrawerOpenings] ebenso. Bei unklarem Ausgang * (`outcome: 'unknown'`) denselben Vorgang mit **demselben** Schluessel noch * einmal senden; er wirkt genau einmal. Ein neuer Schluessel ([newIdempotencyKey]) * gehoert nur zu einem neuen Vorgang. * * **Vor dem Senden geprueft wird nur, was ohne Netz sicher falsch ist:** * fehlende Kennungen, ein fehlender Schluessel, Betraege, die keine Ganzzahl * sind, eine leere Liste. Alles Fachliche (Katalog, Pflichtangaben je Art, * Kassenstand, Anspruch) prueft der Server und meldet es mit seinem Code. */ export interface GetMyDrawerStateOptions { /** Ohne Angabe gilt die Hauptlade der Kasse (`cashregisterId`, beim Kassen-Benutzer-Weg die Kasse der Anmeldung). */ drawerId?: string; cashregisterId?: string; } export interface OpenMyShiftOptions { /** Bei „Erneut senden“ derselbe Schluessel wie beim ersten Versuch. */ idempotencyKey: string; drawerId: string; /** * Gezaehltes Startgeld in Cent (`0` erlaubt). Genau eines von * `openingFloatCents` und `takeOver: true`. */ openingFloatCents?: number; /** Stueckelung zum gezaehlten Startgeld; die Summe muss stimmen ([sumDenominations]). */ denominations?: Denominations | null; /** Den Bestand der Vorschicht ungezaehlt uebernehmen („Bestand übernehmen“). */ takeOver?: boolean; } export interface RecordMyCashMovementOptions { idempotencyKey: string; drawerId: string; type: ManualMovementType; /** Positiv; das Vorzeichen setzt der Server nach der Art. */ amountCents: number; /** Freiwillig bei `change_in` und `cash_drop` (woher bzw. wohin); ohne Angabe bleibt der Ort leer. */ location?: CashLocation; /** Grund; Pflicht bei `other_in` und `other_out`, hoechstens 200 Zeichen. */ note?: string; /** Kassen-Benutzer, Pflicht bei `tip_payout`. */ recipientId?: string; /** Ziel-Lade, Pflicht bei `transfer_out`. */ targetDrawerId?: string; } /** Eine Oeffnung der Lade, wie die Kasse sie puffert und meldet. */ export interface DrawerOpeningEntry { /** Je Eintrag ein eigener Schluessel: ein zweites Melden zaehlt nicht doppelt. */ idempotencyKey: string; reason: OpeningReason; /** Ging der Impuls an die Lade durch? Fehlgeschlagene werden mit `false` gemeldet. */ ok: boolean; /** Zeit am Geraet: Millisekunden seit 1970 oder ISO 8601. */ deviceTime: number | string; /** Text, Pflicht bei `other`. */ note?: string; /** Beleg bei `sale`. */ receiptId?: string; /** Fehlertext eines fehlgeschlagenen Impulses. */ error?: string; /** Lade der Oeffnung (gepuffert); muss `drawerId` der Anfrage sein, sonst `validation`. */ drawerId?: string; /** * Wer die Lade oeffnete (gepuffert: der damals angemeldete Mitarbeiter). Der * Server nimmt ihn nur, wenn er zum Betrieb gehoert und der Kasse zugewiesen * ist, den Namen aus dem Konto; sonst gilt der sendende Benutzer. */ operator?: { registerUserId: string; name?: string | null; }; } export interface LogMyDrawerOpeningsOptions { drawerId: string; /** 1–50 Eintraege; offline gepufferte Oeffnungen werden spaeter nachgesendet. */ entries: DrawerOpeningEntry[]; } export interface GetMyShiftReportOptions { shiftId: string; } /** Trinkgeld-Auszahlung beim Abschluss: hoechstens der offene Anspruch (`DrawerState.tipClaims`). */ export interface TipPayout { registerUserId: string; cents: number; } export interface CloseMyShiftOptions { idempotencyKey: string; shiftId: string; /** Gezaehltes Bargeld in Cent (`0` erlaubt). */ countedCents: number; denominations?: Denominations | null; /** Wird angenommen, wirkt aber nicht: den Versuch zaehlt der Server (hoechstens zwei). */ attempt?: number; /** Begruendung; Pflicht, wenn die Abweichung die Schwelle uebersteigt (`comment_required`). */ comment?: string; tipPayouts?: TipPayout[]; /** * Nach dem Zaehlen Geld entnehmen (`cash_drop`) oder einlegen (`change_in`), * `amountCents` positiv. Entnehmen hoechstens den gezaehlten Betrag * (`cash_movement_exceeds_balance`); ein Betrag ueber 0 braucht das Recht * `cashMove` (`after_count_not_permitted`). `0` oder ohne Angabe: alles * bleibt in der Lade. Gebucht wird nur beim tatsaechlichen Schliessen, nie bei * `recount`; die Antwort traegt dann `afterCountReceipt` („Bon fürs Kuvert“). */ afterCount?: AfterCountOption | null; /** * Nur pruefen, nicht schliessen: dieselbe Pruefung wie beim Schliessen, damit * die Kasse vor „Geld entnehmen“ weiss, ob nachgezaehlt (`recount`) oder * begruendet (`comment_required`) werden muss. Antwort `ready`, wenn das * Schliessen mit diesem Betrag ginge; gebucht wird nichts (auch kein * `afterCount`). Die Zaehlung zaehlt als einer der zwei Versuche; schliesst * danach derselbe Betrag, gilt er als dieselbe Zaehlung. */ checkOnly?: boolean; } /** Entnehmen oder Einlegen beim Abschluss (siehe [CloseMyShiftOptions.afterCount]). */ export interface AfterCountOption { type: AfterCountType; amountCents: number; } /** Stand der Lade: Rechte, offene Schicht, Trinkgeld-Ansprueche und (mit `cashView`) Soll und letzte Oeffnungen. */ export declare function getMyDrawerState(transport: InternerTransport, options?: GetMyDrawerStateOptions): Promise; /** Schicht oeffnen: gezaehltes Startgeld oder den Bestand uebernehmen (Recht `shift`). */ export declare function openMyShift(transport: InternerTransport, options: OpenMyShiftOptions): Promise; /** Ein- oder Auszahlung buchen (Recht `cashMove`); Antwort mit den Bon-Daten „Kassenbewegung“. */ export declare function recordMyCashMovement(transport: InternerTransport, options: RecordMyCashMovementOptions): Promise; /** Oeffnungen der Lade melden (auch nachgesendet); doppelt gemeldete zaehlen einmal. */ export declare function logMyDrawerOpenings(transport: InternerTransport, options: LogMyDrawerOpeningsOptions): Promise; /** Bericht der Schicht: Schicht, Bewegungen und Bon-Daten (X-Bon, bei geschlossener Schicht der Z-Bon). */ export declare function getMyShiftReport(transport: InternerTransport, options: GetMyShiftReportOptions): Promise; /** * Schicht schliessen (Recht `shift`). `status: 'recount'` heisst: bitte noch * einmal zaehlen und erneut senden (kein Fehler); nach dem zweiten Zaehlen * schliesst der Server, bei grosser Abweichung nur mit `comment`. Mit * `checkOnly` nur pruefen: `status: 'ready'` statt Schliessen. */ export declare function closeMyShift(transport: InternerTransport, options: CloseMyShiftOptions): Promise; /** * Summe einer Stueckelung in Cent, oder `null`, wenn sie keine ist: ein * Schluessel, der kein Euro-Wert ist ([EUR_DENOMINATIONS], genau so * geschrieben, `"500"`, nicht `"0500"`), eine Anzahl, die keine ganze Zahl * von 0 bis 100 000 ist. Dieselbe Regel wie am Server * (`invalid_denominations`). Gemeinsame Faelle mit dem Dart-Zwilling: * `fixtures/shift-cases.json`. */ export declare function sumDenominations(denominations: Readonly>): number | null; /** * Ein eingetippter Betrag in Cent, **ohne Gleitkomma**: `'12,5'` → `1250`, * `'0'` → `0` (anders als beim Kassieren ist 0 hier gueltig: eine leere Lade, * kein Startgeld). Dezimaltrenner Komma oder Punkt mit einer oder zwei * Nachkommastellen; `null` fuer leer, Vorzeichen, Tausendertrenner * (`'1.000'`, `'1 000'`), drei Nachkommastellen, Euro-Zeichen und alles * ueber einer sicheren Ganzzahl. Gemeinsame Faelle mit dem Dart-Zwilling: * `fixtures/shift-cases.json`. */ export declare function parseCentsAllowZero(text: string): number | null; /** * Ein frischer Idempotenzschluessel fuer einen neuen Vorgang: `kasse-` und * 32 Hex-Zeichen aus dem sicheren Zufall (`crypto.getRandomValues`), dieselbe * Form wie beim Zaehlen der Inventur in der Kassen-App. Fuer „Erneut senden“ * nie einen neuen ziehen, sondern den alten behalten. */ export declare function newIdempotencyKey(): string; /** Zeilen des Trinkgelds eines Mitarbeiters (siehe [shiftTipLines]). */ export type ShiftTipLineKey = 'shift_receipt.tip_carried_over' | 'shift_receipt.tip_earned' | 'shift_receipt.tip_retained' | 'shift_receipt.tip_paid_out' | 'shift_receipt.tip_refunded_by_employee' | 'shift_receipt.tip_open'; export interface ShiftTipLine { key: ShiftTipLineKey; /** Das Wort aus dem Katalog ([labelText]). */ text: string; cents: number; } /** * Was vom Trinkgeld eines Mitarbeiters dasteht – auf dem Bon, im Kassenstand * und beim Abschluss gleich (Rulings R50/R51): „verdient“ (sofort + über * Lohn) immer, „über Lohn“, „schon genommen“, „selbst zurückgegeben“ (R62) * und „offen“ nur, wenn nicht 0. Davor „aus früheren Schichten“ (R64, nur ≠ 0): * offen = aus früheren Schichten + verdient − über Lohn − schon genommen + * selbst zurückgegeben. * Ist alles 0, gibt es keine Zeile, und der Mitarbeiter entfaellt ganz. Ohne * `openCents` (Laufstand) zaehlt offen als 0. Gemeinsame Faelle mit dem * Dart-Zwilling: `fixtures/shift-cases.json`. */ export declare function shiftTipLines(tip: Omit & { refundedByEmployeeCents?: number; carriedOverCents?: number; openCents?: number; }): ShiftTipLine[]; /** * Dauer für Menschen aus ganzen Minuten: unter 1 Std. „45 Min.“, unter 1 Tag * „8 Std. 32 Min.“ (bei 0 Minuten nur „8 Std.“), ab 1 Tag „1 Tag 3 Std.“ bzw. * „2 Tage“ (bei 0 Stunden ohne Stunden). Negatives und Unsinn zählt als 0; * Bruchteile werden abgeschnitten. Gemeinsame Fälle mit dem Dart-Zwilling: * `fixtures/shift-cases.json` (`durationText`). */ export declare function durationText(minutes: number): string;