@kreiseck/kasseneck-api 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,98 @@ Was vor 0.7.0 geschah, steht in der Commit-Historie (`git log`); ab hier wird
4
4
  es hier geführt. Ein Eintrag nennt die Änderung **und ihren Grund** —
5
5
  nur der Grund überlebt den nächsten Umbau.
6
6
 
7
+ ## 0.9.2
8
+
9
+ ### Sechzehn Saetze: einen Beleg weitergeben, und der Drucker-Wizard
10
+
11
+ **Anlass:** Ein alter Beleg soll sich weitergeben lassen — Link kopieren,
12
+ teilen, per E-Mail senden — und der Drucker richtet sich kuenftig ueber einen
13
+ Wizard ein, der erst testet und bestaetigen laesst und dann speichert. Beides
14
+ entsteht **gleichzeitig** in der Browser-Kasse und in der Kassen-App. Ohne
15
+ diese Schluessel haetten beide Seiten dieselben sieben Lagen unabhaengig
16
+ formuliert, und der Kassier haette zwei verschiedene Woerter fuer dieselbe
17
+ Sache gelesen — genau das, wogegen es diesen Katalog gibt.
18
+
19
+ - **Beleg weitergeben:** `beleg.link_kopiert`, `beleg.teilen_text`
20
+ (`betrieb`, `nummer`, `betrag`, `link`), `beleg.nicht_teilbar`,
21
+ `beleg.test_hinweis_teilen`.
22
+ - **Per E-Mail senden:** `beleg.mail_gesendet` (`an`) und die vier Ausgaenge
23
+ `beleg.mail_adresse_ungueltig`, `beleg.mail_zu_oft`,
24
+ `beleg.mail_fehlgeschlagen`, `beleg.mail_nicht_gefunden`.
25
+ - **Drucker-Wizard** (beide Kassen, deshalb ohne `nur`):
26
+ `druck.wizard_verbinden` (`name`), `druck.wizard_testdruck_frage`,
27
+ `druck.wizard_qr_frage`, `druck.wizard_qr_keiner_hinweis`,
28
+ `druck.wizard_nichts_gekommen`, `druck.wizard_gespeichert` (`name`),
29
+ `druck.wizard_abgebrochen`.
30
+
31
+ **Neu: `BELEG_MAIL_FEHLER` und `belegMailFehler(code)`** — die Zuordnung vom
32
+ `code` des Backends (`adresse_ungueltig`, `zu_oft`, `versand_fehlgeschlagen`,
33
+ `beleg_nicht_gefunden`) auf den Satz. Grund: die vier Ausgaenge verlangen vom
34
+ Kassier vier verschiedene Handlungen, und beide Kassen sollen am **Code**
35
+ entscheiden statt an einer Formulierung, die sich im Backend jederzeit aendern
36
+ darf. Ein unbekannter Code faellt auf `beleg.mail_fehlgeschlagen` zurueck — ein
37
+ leerer Schirm waere schlimmer als ein zu allgemeiner Satz. Die Zuordnung steht
38
+ als `belegMailFehler` mit in `fixtures/kasse-texte.json`, weil die App den
39
+ Katalog aus dem Tarball liest und das Web die Quelle direkt importiert.
40
+
41
+ Bewusst ein Objekt und **keine** Liste in Grossschrift: der
42
+ Oberflaechen-Vertrag liest jede exportierte Liste als Enum der
43
+ Kasseneinstellungen ein, und der Dart-Zwilling schickt deren Werte durch
44
+ `KasseSettings.aus`. Fehlercodes haetten dort nichts verloren.
45
+
46
+ **Abweichung von der Vorlage, bewusst:** `beleg.mail_nicht_gefunden` sagt
47
+ „Dieser Beleg wurde nicht gefunden — er konnte nicht gesendet werden." und
48
+ nicht denselben Satz wie das schon vorhandene `beleg.nicht_gefunden`. Dort
49
+ scheitert das Oeffnen, hier das Senden; der Kassier steht vor einem Adressfeld
50
+ und muss lesen, dass nichts hinausgegangen ist. Ein Satz zweimal im Katalog
51
+ faellt ohnehin schon seit 0.9.1 im Test auf.
52
+
53
+ **Neue abgeleitete Pruefungen:** kein Satz zum Weitergeben eines Belegs ist an
54
+ eine Seite gebunden; der Teilen-Text traegt den Link, und zwar am Schluss;
55
+ jeder platzhalterlose `beleg.mail_`-Satz haengt an genau einem Backend-Code (und
56
+ kein Code an zweien); der einzige `beleg.mail_`-Satz mit Platzhalter ist der
57
+ ueber das Gelingen; jeder Satz des Wizards gilt auf beiden Seiten.
58
+
59
+ `FEHLERREGELN` bleibt unveraendert: die Codes sind die Verfeinerung **eines**
60
+ Aufrufs (`sendReceiptEmail`), keine neue Art, einen Transportfehler
61
+ einzuordnen.
62
+
63
+ ## 0.9.1
64
+
65
+ ### Elf Saetze fuer die vier Ausgaenge einer Kartenzahlung und das Terminal-Protokoll
66
+
67
+ **Anlass:** Die Kassen-App bekommt GP Tom mit denselben vier Ausgaengen, die
68
+ die Browser-Kasse schon kennt — geglueckt, abgebrochen, gescheitert, unklar —
69
+ und dazu ein Terminal-Protokoll. Beide Kassen duerfen nur Katalogsaetze zeigen;
70
+ ohne diese Schluessel haette die App eigene Formulierungen erfunden, und der
71
+ Kassier haette am Tresen zwei verschiedene Woerter fuer dieselbe Lage gelesen.
72
+
73
+ **Grund fuer die Auswahl:** Der teuerste Fehler an der Kasse ist die zweite
74
+ Belastung derselben Karte. Deshalb tragen die neuen Saetze zu den unsicheren
75
+ Ausgaengen alles, was der Kassier braucht, um NICHT zu wiederholen: Betrag,
76
+ Kennung und den Hinweis auf den Terminal-Beleg.
77
+
78
+ - **GP Tom** (nur App, wie die uebrigen `gptom.`-Saetze): `gptom.abgelehnt` und
79
+ `gptom.abgelehnt_mit_code` (das Terminal hat entschieden — sicher nichts
80
+ gebucht), `gptom.nicht_geoeffnet` (die App liess sich nicht starten),
81
+ `gptom.zeit_abgelaufen` / `gptom.zeit_abgelaufen_mit_kennung` (Frist abgelaufen
82
+ ist **kein** Abbruch: die Karte kann belastet sein).
83
+ - **Karte gebucht, Beleg fehlt:** `kartenzahlung.karte_gebucht_beleg_offen` und
84
+ `kartenzahlung.karte_gebucht_korb_geaendert`, beide mit `betrag` und `kennung`.
85
+ Der zweite nennt die Entscheidung, die er verlangt: Beleg erstellen oder am
86
+ Terminal stornieren und hier verwerfen.
87
+ - **Warteschirm:** `kartenzahlung.wartet_auf_terminal`.
88
+ - **Terminal-Protokoll:** `protokoll.leer`, `protokoll.kopiert` — ohne `nur`,
89
+ weil an dem Satz nichts plattformgebunden ist.
90
+
91
+ **Neue abgeleitete Pruefungen** statt einer gepflegten Liste: kein Satz steht
92
+ zweimal im Katalog; jeder `gptom.`-Satz gilt nur in der App; jede Fassung
93
+ `…_mit_kennung` ist ihre Grundfassung plus dem Anker und teilt deren `nur`;
94
+ jeder unklare Ausgang warnt vor dem zweiten Kassieren.
95
+
96
+ `FEHLERREGELN` bleibt unveraendert — die neuen Saetze sind Ausgaenge einer
97
+ Kartenzahlung, keine neue Art, einen Transportfehler einzuordnen.
98
+
7
99
  ## 0.9.0
8
100
 
9
101
  ### Alle Kartenzahlungsbloecke im Belegmodell — nicht nur Hobex
@@ -10,4 +10,4 @@ export { verteileRabatt } from '../receipt/discount.js';
10
10
  export { cancelScopeOf, receiptsScopeOf, type RegisterScope, type RegisterUserPerms } from '../register/pairing.js';
11
11
  export { type NetzDrucker, type DruckJob, type DruckJobStatus, type CreatePrintJobOptions, listMyPrinters, createPrintJob, getPrintJob } from './drucker.js';
12
12
  export { listMyTipRecipients } from './trinkgeld.js';
13
- export { MELDUNGEN, FEHLERREGELN, meldung, meldungGiltFuer, type Meldung, type MeldungsSchluessel, type Fehlerart, type Seite, } from './texte.js';
13
+ export { MELDUNGEN, FEHLERREGELN, meldung, meldungGiltFuer, BELEG_MAIL_FEHLER, belegMailFehler, type Meldung, type MeldungsSchluessel, type Fehlerart, type Seite, type BelegMailFehlercode, } from './texte.js';
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getPrintJob = exports.createPrintJob = exports.listMyPrinters = exports.receiptsScopeOf = exports.cancelScopeOf = exports.verteileRabatt = exports.setMyRegisterDeviceSettings = exports.setMyKasseSettings = exports.getKasseSettings = exports.mengeErlaubt = exports.mengenVorgabe = exports.mengenregelFuerEinheit = exports.listMyArticles = exports.listMyArticleGroups = exports.fromKasseArtikelPayload = exports.fromArticleGroupPayload = exports.FERTIG_SEKUNDEN = exports.WZ_SKALA = exports.LOGO_SKALA = exports.WZ_STAERKE = exports.WZ_SEITE = exports.RABATT = exports.AUTO_AB_MIN = exports.KACHELSTIL = exports.SCHRIFT_EINST = exports.LOGO_GROESSE = exports.TASTEN_AKTIONEN = exports.LADE_AUTO = exports.SCHNITT = exports.ZEICHENSATZ = exports.PAPIER = exports.TERMINAL_ART = exports.TERMINAL_VIA = exports.DRUCKER_ART = exports.HOEHE = exports.KATPOS = exports.LAYOUT = exports.BELEG_AUSGABE = exports.KASSIEREN_MODUS = exports.TG_MODUS = exports.MENGE = exports.WASSERZEICHEN = exports.SCHRIFT = exports.STIL = exports.mergeKasseSettings = exports.KASSE_GERAET_STANDARD = exports.KASSE_BETRIEB_STANDARD = exports.KASSE_TASTEN_STANDARD = exports.KASSE_TASTEN_AKTIONEN = exports.KARTENANBIETER = void 0;
4
- exports.meldungGiltFuer = exports.meldung = exports.FEHLERREGELN = exports.MELDUNGEN = exports.listMyTipRecipients = void 0;
4
+ exports.belegMailFehler = exports.BELEG_MAIL_FEHLER = exports.meldungGiltFuer = exports.meldung = exports.FEHLERREGELN = exports.MELDUNGEN = exports.listMyTipRecipients = void 0;
5
5
  /**
6
6
  * Kachel-Kasse: Einstellungen, Artikelgruppen/Artikel fuer Kacheln,
7
7
  * Rabattverteilung. Die Aufrufe heissen 1:1 wie die Backend-Functions
@@ -74,3 +74,5 @@ Object.defineProperty(exports, "MELDUNGEN", { enumerable: true, get: function ()
74
74
  Object.defineProperty(exports, "FEHLERREGELN", { enumerable: true, get: function () { return texte_js_1.FEHLERREGELN; } });
75
75
  Object.defineProperty(exports, "meldung", { enumerable: true, get: function () { return texte_js_1.meldung; } });
76
76
  Object.defineProperty(exports, "meldungGiltFuer", { enumerable: true, get: function () { return texte_js_1.meldungGiltFuer; } });
77
+ Object.defineProperty(exports, "BELEG_MAIL_FEHLER", { enumerable: true, get: function () { return texte_js_1.BELEG_MAIL_FEHLER; } });
78
+ Object.defineProperty(exports, "belegMailFehler", { enumerable: true, get: function () { return texte_js_1.belegMailFehler; } });
@@ -124,6 +124,17 @@ declare const MELDUNGEN_ROH: {
124
124
  readonly text: "Unklar, ob die Kartenzahlung durchgegangen ist — die Verbindung zum Terminal riss ab. Bitte am Terminal-Beleg nachsehen, BEVOR neu kassiert wird: die Karte kann belastet sein. Kennung der Zahlung: {kennung}.";
125
125
  readonly platzhalter: readonly ["kennung"];
126
126
  };
127
+ readonly 'kartenzahlung.wartet_auf_terminal': {
128
+ readonly text: "Bitte am Terminal fortfahren …";
129
+ };
130
+ readonly 'kartenzahlung.karte_gebucht_beleg_offen': {
131
+ readonly text: "Die Karte ist bereits mit {betrag} belastet (Kennung {kennung}) — der Beleg dazu fehlt noch. Bitte jetzt den Beleg erstellen und nicht erneut kassieren.";
132
+ readonly platzhalter: readonly ["betrag", "kennung"];
133
+ };
134
+ readonly 'kartenzahlung.karte_gebucht_korb_geaendert': {
135
+ readonly text: "Es gibt eine gebuchte Kartenzahlung über {betrag} (Kennung {kennung}), aber der Korb hat sich seither geändert. Bitte zuerst entscheiden: den Beleg zur gebuchten Zahlung erstellen oder die Zahlung am Terminal stornieren und hier verwerfen.";
136
+ readonly platzhalter: readonly ["betrag", "kennung"];
137
+ };
127
138
  readonly 'kartenzahlung.connect_nicht_verbunden': {
128
139
  readonly text: "Kartenzahlung nicht möglich: Kasseneck Connect ist nicht verbunden — Einstellungen → Kasseneck Connect.";
129
140
  readonly nur: readonly ["web"];
@@ -161,6 +172,34 @@ declare const MELDUNGEN_ROH: {
161
172
  readonly platzhalter: readonly ["code"];
162
173
  readonly nur: readonly ["app"];
163
174
  };
175
+ readonly 'gptom.abgelehnt': {
176
+ readonly text: "Das Terminal hat die Zahlung abgelehnt.";
177
+ readonly nur: readonly ["app"];
178
+ };
179
+ readonly 'gptom.abgelehnt_mit_code': {
180
+ readonly text: "Das Terminal hat die Zahlung abgelehnt ({code}).";
181
+ readonly platzhalter: readonly ["code"];
182
+ readonly nur: readonly ["app"];
183
+ };
184
+ readonly 'gptom.nicht_geoeffnet': {
185
+ readonly text: "GP Tom ließ sich nicht öffnen — bitte die GP-Tom-App prüfen und erneut versuchen.";
186
+ readonly nur: readonly ["app"];
187
+ };
188
+ readonly 'gptom.zeit_abgelaufen': {
189
+ readonly text: "Das Terminal hat in der Frist nicht geantwortet — die Karte kann belastet sein. Bitte am Terminal-Beleg nachsehen, BEVOR neu kassiert wird.";
190
+ readonly nur: readonly ["app"];
191
+ };
192
+ readonly 'gptom.zeit_abgelaufen_mit_kennung': {
193
+ readonly text: "Das Terminal hat in der Frist nicht geantwortet — die Karte kann belastet sein. Bitte am Terminal-Beleg nachsehen, BEVOR neu kassiert wird. Kennung der Zahlung: {kennung}.";
194
+ readonly platzhalter: readonly ["kennung"];
195
+ readonly nur: readonly ["app"];
196
+ };
197
+ readonly 'protokoll.leer': {
198
+ readonly text: "Noch keine Einträge — das Protokoll füllt sich mit der ersten Kartenzahlung.";
199
+ };
200
+ readonly 'protokoll.kopiert': {
201
+ readonly text: "Das Protokoll liegt in der Zwischenablage.";
202
+ };
164
203
  readonly 'belege.laden_fehlgeschlagen': {
165
204
  readonly text: "Die Belege konnten nicht geladen werden.";
166
205
  };
@@ -182,6 +221,35 @@ declare const MELDUNGEN_ROH: {
182
221
  readonly 'storno.position_fehlt': {
183
222
  readonly text: "Bitte mindestens eine Position wählen.";
184
223
  };
224
+ readonly 'beleg.link_kopiert': {
225
+ readonly text: "Der Link zum Beleg liegt in der Zwischenablage.";
226
+ };
227
+ readonly 'beleg.teilen_text': {
228
+ readonly text: "Beleg {nummer} von {betrieb} über {betrag}: {link}";
229
+ readonly platzhalter: readonly ["betrieb", "nummer", "betrag", "link"];
230
+ };
231
+ readonly 'beleg.nicht_teilbar': {
232
+ readonly text: "Für diesen Beleg gibt es keinen Link — er stammt aus einer älteren Kasse.";
233
+ };
234
+ readonly 'beleg.test_hinweis_teilen': {
235
+ readonly text: "Test-Umgebung — der Beleg ist steuerlich nicht gültig.";
236
+ };
237
+ readonly 'beleg.mail_gesendet': {
238
+ readonly text: "Der Beleg wurde an {an} gesendet.";
239
+ readonly platzhalter: readonly ["an"];
240
+ };
241
+ readonly 'beleg.mail_adresse_ungueltig': {
242
+ readonly text: "Diese E-Mail-Adresse ist nicht gültig.";
243
+ };
244
+ readonly 'beleg.mail_zu_oft': {
245
+ readonly text: "Dieser Beleg wurde schon oft gesendet — bitte später noch einmal.";
246
+ };
247
+ readonly 'beleg.mail_fehlgeschlagen': {
248
+ readonly text: "Der Beleg konnte nicht gesendet werden. Bitte noch einmal versuchen.";
249
+ };
250
+ readonly 'beleg.mail_nicht_gefunden': {
251
+ readonly text: "Dieser Beleg wurde nicht gefunden — er konnte nicht gesendet werden.";
252
+ };
185
253
  readonly 'druck.fehlgeschlagen': {
186
254
  readonly text: "Der Ausdruck ist fehlgeschlagen.";
187
255
  };
@@ -220,6 +288,29 @@ declare const MELDUNGEN_ROH: {
220
288
  readonly platzhalter: readonly ["weg"];
221
289
  readonly nur: readonly ["web"];
222
290
  };
291
+ readonly 'druck.wizard_verbinden': {
292
+ readonly text: "Verbinde mit {name} …";
293
+ readonly platzhalter: readonly ["name"];
294
+ };
295
+ readonly 'druck.wizard_testdruck_frage': {
296
+ readonly text: "Ist der Testdruck gekommen?";
297
+ };
298
+ readonly 'druck.wizard_qr_frage': {
299
+ readonly text: "Welcher QR-Code ist sauber gedruckt?";
300
+ };
301
+ readonly 'druck.wizard_qr_keiner_hinweis': {
302
+ readonly text: "Kein QR-Code kam sauber — der Beleg zeigt den QR-Code dann am Bildschirm.";
303
+ };
304
+ readonly 'druck.wizard_nichts_gekommen': {
305
+ readonly text: "Nichts gekommen? Drucker an, Papier drin, richtiges Gerät gewählt?";
306
+ };
307
+ readonly 'druck.wizard_gespeichert': {
308
+ readonly text: "{name} ist eingerichtet.";
309
+ readonly platzhalter: readonly ["name"];
310
+ };
311
+ readonly 'druck.wizard_abgebrochen': {
312
+ readonly text: "Nichts gespeichert.";
313
+ };
223
314
  readonly 'bluetooth.aus': {
224
315
  readonly text: "Bluetooth ist ausgeschaltet. Bitte einschalten und erneut suchen.";
225
316
  readonly nur: readonly ["app"];
@@ -329,6 +420,37 @@ export declare const FEHLERREGELN: readonly [{
329
420
  readonly verhalten: "ersatz";
330
421
  }];
331
422
  export type Fehlerart = (typeof FEHLERREGELN)[number]['art'];
423
+ /**
424
+ * Beleg per E-Mail senden: welcher `code` des Backends welchen Satz bekommt.
425
+ *
426
+ * `FEHLERREGELN` bleibt davon unberuehrt — das hier ist keine neue Art, einen
427
+ * Transportfehler einzuordnen, sondern die Verfeinerung EINES Aufrufs
428
+ * (`sendReceiptEmail`). Die vier Ausgaenge sind fuer den Kassier vier
429
+ * verschiedene Handlungen: Adresse verbessern, spaeter noch einmal, noch
430
+ * einmal senden, Beleg suchen. Beide Kassen entscheiden am `code`, nicht am
431
+ * Satz des Backends — sonst haengt das Wort am Tresen an einer Formulierung,
432
+ * die sich im Backend jederzeit aendern darf.
433
+ *
434
+ * Bewusst ein Objekt und keine Liste in GROSSSCHRIFT: der
435
+ * Oberflaechen-Vertrag (`fixtures/oberflaeche.json`) liest jede exportierte
436
+ * Liste als Enum der Kasseneinstellungen ein, und der Dart-Zwilling schickt
437
+ * deren Werte durch `KasseSettings.aus`. Fehlercodes haben dort nichts
438
+ * verloren; sie stehen in `fixtures/kasse-texte.json`.
439
+ */
440
+ export declare const BELEG_MAIL_FEHLER: {
441
+ readonly adresse_ungueltig: "beleg.mail_adresse_ungueltig";
442
+ readonly zu_oft: "beleg.mail_zu_oft";
443
+ readonly versand_fehlgeschlagen: "beleg.mail_fehlgeschlagen";
444
+ readonly beleg_nicht_gefunden: "beleg.mail_nicht_gefunden";
445
+ };
446
+ export type BelegMailFehlercode = keyof typeof BELEG_MAIL_FEHLER;
447
+ /**
448
+ * Der Satz zu einem `code` des Backends. Einen Code, den dieses Paket noch
449
+ * nicht kennt, faengt der allgemeine Satz auf: das Senden ist gescheitert und
450
+ * darf wiederholt werden. Ein leerer Schirm waere schlimmer als ein zu
451
+ * allgemeiner Satz.
452
+ */
453
+ export declare function belegMailFehler(code: string | undefined | null): MeldungsSchluessel;
332
454
  /** Der Satz zum Schluessel, Platzhalter ersetzt. Fehlt ein Wert, wirft es — ein `{status}` am Tresen waere schlimmer. */
333
455
  export declare function meldung(schluessel: MeldungsSchluessel, werte?: Record<string, string | number>): string;
334
456
  /** Gilt der Satz auf dieser Seite? */
@@ -16,7 +16,8 @@
16
16
  * auf einer Plattform vorkommen kann.
17
17
  */
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.FEHLERREGELN = exports.MELDUNGEN = void 0;
19
+ exports.BELEG_MAIL_FEHLER = exports.FEHLERREGELN = exports.MELDUNGEN = void 0;
20
+ exports.belegMailFehler = belegMailFehler;
20
21
  exports.meldung = meldung;
21
22
  exports.meldungGiltFuer = meldungGiltFuer;
22
23
  const MELDUNGEN_ROH = {
@@ -59,6 +60,13 @@ const MELDUNGEN_ROH = {
59
60
  'kartenzahlung.unklar': { text: 'Unklar, ob die Kartenzahlung durchgegangen ist — die Verbindung zum Terminal riss ab. Bitte am Terminal-Beleg nachsehen, BEVOR neu kassiert wird: die Karte kann belastet sein.' },
60
61
  // Die Kennung ist der einzige Anker, um die Zahlung am Terminal-Beleg wiederzufinden — liegt sie vor, gilt dieser Satz statt kartenzahlung.unklar.
61
62
  'kartenzahlung.unklar_mit_kennung': { text: 'Unklar, ob die Kartenzahlung durchgegangen ist — die Verbindung zum Terminal riss ab. Bitte am Terminal-Beleg nachsehen, BEVOR neu kassiert wird: die Karte kann belastet sein. Kennung der Zahlung: {kennung}.', platzhalter: ['kennung'] },
63
+ 'kartenzahlung.wartet_auf_terminal': { text: 'Bitte am Terminal fortfahren …' },
64
+ // Ein geglücktes Kartenergebnis ohne Beleg ist der teuerste Zustand am Tresen:
65
+ // wer hier erneut kassiert, belastet die Karte ein zweites Mal. Beide Sätze
66
+ // nennen deshalb Betrag UND Kennung — nur damit findet der Kassier die Zahlung
67
+ // am Terminal-Beleg wieder — und keiner rät zum Wiederholen.
68
+ 'kartenzahlung.karte_gebucht_beleg_offen': { text: 'Die Karte ist bereits mit {betrag} belastet (Kennung {kennung}) — der Beleg dazu fehlt noch. Bitte jetzt den Beleg erstellen und nicht erneut kassieren.', platzhalter: ['betrag', 'kennung'] },
69
+ 'kartenzahlung.karte_gebucht_korb_geaendert': { text: 'Es gibt eine gebuchte Kartenzahlung über {betrag} (Kennung {kennung}), aber der Korb hat sich seither geändert. Bitte zuerst entscheiden: den Beleg zur gebuchten Zahlung erstellen oder die Zahlung am Terminal stornieren und hier verwerfen.', platzhalter: ['betrag', 'kennung'] },
62
70
  'kartenzahlung.connect_nicht_verbunden': { text: 'Kartenzahlung nicht möglich: Kasseneck Connect ist nicht verbunden — Einstellungen → Kasseneck Connect.', nur: ['web'] },
63
71
  'terminal.keines_gefunden': { text: 'Kein Hobex-Terminal gefunden — ist es eingeschaltet und im selben Netz wie dieser Rechner?', nur: ['web'] },
64
72
  'terminal.nicht_bereit': { text: 'Terminal antwortet, ist aber nicht betriebsbereit: {antwort} — TID prüfen.', platzhalter: ['antwort'], nur: ['web'] },
@@ -67,6 +75,19 @@ const MELDUNGEN_ROH = {
67
75
  'gptom.zahlung_fehlgeschlagen': { text: 'GP Tom: Zahlung fehlgeschlagen: {grund}', platzhalter: ['grund'], nur: ['app'] },
68
76
  'gptom.terminal_antwortet_nicht': { text: 'Das Terminal hat nicht geantwortet: {grund}', platzhalter: ['grund'], nur: ['app'] },
69
77
  'gptom.zahlung_nicht_abgeschlossen': { text: 'Die Zahlung wurde nicht abgeschlossen ({code}).', platzhalter: ['code'], nur: ['app'] },
78
+ // Abgelehnt heißt: das Terminal hat entschieden, es ist sicher nichts gebucht.
79
+ // Der Code ist die einzige Handhabe, mit der der Inhaber bei GP nachfragen kann —
80
+ // liegt einer vor, gilt die Fassung mit Code.
81
+ 'gptom.abgelehnt': { text: 'Das Terminal hat die Zahlung abgelehnt.', nur: ['app'] },
82
+ 'gptom.abgelehnt_mit_code': { text: 'Das Terminal hat die Zahlung abgelehnt ({code}).', platzhalter: ['code'], nur: ['app'] },
83
+ 'gptom.nicht_geoeffnet': { text: 'GP Tom ließ sich nicht öffnen — bitte die GP-Tom-App prüfen und erneut versuchen.', nur: ['app'] },
84
+ // Frist abgelaufen ist kein Abbruch: die Karte kann belastet sein, nur die
85
+ // Antwort blieb aus. Deshalb derselbe Ton wie kartenzahlung.unklar.
86
+ 'gptom.zeit_abgelaufen': { text: 'Das Terminal hat in der Frist nicht geantwortet — die Karte kann belastet sein. Bitte am Terminal-Beleg nachsehen, BEVOR neu kassiert wird.', nur: ['app'] },
87
+ 'gptom.zeit_abgelaufen_mit_kennung': { text: 'Das Terminal hat in der Frist nicht geantwortet — die Karte kann belastet sein. Bitte am Terminal-Beleg nachsehen, BEVOR neu kassiert wird. Kennung der Zahlung: {kennung}.', platzhalter: ['kennung'], nur: ['app'] },
88
+ // --- Terminal-Protokoll --------------------------------------------------
89
+ 'protokoll.leer': { text: 'Noch keine Einträge — das Protokoll füllt sich mit der ersten Kartenzahlung.' },
90
+ 'protokoll.kopiert': { text: 'Das Protokoll liegt in der Zwischenablage.' },
70
91
  // --- Belege und Storno ---------------------------------------------------
71
92
  'belege.laden_fehlgeschlagen': { text: 'Die Belege konnten nicht geladen werden.' },
72
93
  'belege.keine_im_zeitraum': { text: 'Keine Belege in diesem Zeitraum.' },
@@ -75,6 +96,30 @@ const MELDUNGEN_ROH = {
75
96
  'storno.fehlgeschlagen': { text: 'Das Storno ist fehlgeschlagen.' },
76
97
  'storno.grund_fehlt': { text: 'Bitte einen Grund wählen.' },
77
98
  'storno.position_fehlt': { text: 'Bitte mindestens eine Position wählen.' },
99
+ // --- Beleg weitergeben: Link, Teilen, E-Mail -----------------------------
100
+ // Kopieren, Teilen und Senden fuehren zu demselben Ziel: der oeffentlichen
101
+ // Belegseite (beleg.kasseneck.at/<fullReceiptId>). Kein Satz davon ist
102
+ // plattformgebunden — nur die Huelle unterscheidet sich, nicht das Wort.
103
+ 'beleg.link_kopiert': { text: 'Der Link zum Beleg liegt in der Zwischenablage.' },
104
+ // Der Text, der beim Teilen mitgeht. Der Link steht am Schluss, damit ihn
105
+ // jede Huelle (SMS, Messenger, Mail) bis zum Ende als Link erkennt und nicht
106
+ // mitten im Satz abbricht.
107
+ 'beleg.teilen_text': { text: 'Beleg {nummer} von {betrieb} über {betrag}: {link}', platzhalter: ['betrieb', 'nummer', 'betrag', 'link'] },
108
+ // Belege aus dem Altbestand tragen keine `fullReceiptId`; ohne sie gibt es
109
+ // keine Belegseite. Der Satz nennt den Grund, sonst sucht der Kassier den
110
+ // Fehler bei sich und versucht es ein zweites Mal.
111
+ 'beleg.nicht_teilbar': { text: 'Für diesen Beleg gibt es keinen Link — er stammt aus einer älteren Kasse.' },
112
+ // Ein Testbeleg hat eine Belegseite, ist aber steuerlich nichts wert. Wer
113
+ // den Link weitergibt, muss das vorher lesen, nicht hinterher.
114
+ 'beleg.test_hinweis_teilen': { text: 'Test-Umgebung — der Beleg ist steuerlich nicht gültig.' },
115
+ 'beleg.mail_gesendet': { text: 'Der Beleg wurde an {an} gesendet.', platzhalter: ['an'] },
116
+ 'beleg.mail_adresse_ungueltig': { text: 'Diese E-Mail-Adresse ist nicht gültig.' },
117
+ 'beleg.mail_zu_oft': { text: 'Dieser Beleg wurde schon oft gesendet — bitte später noch einmal.' },
118
+ 'beleg.mail_fehlgeschlagen': { text: 'Der Beleg konnte nicht gesendet werden. Bitte noch einmal versuchen.' },
119
+ // Bewusst nicht derselbe Satz wie `beleg.nicht_gefunden`: dort scheitert das
120
+ // Oeffnen, hier das Senden. Der Kassier steht vor einem Adressfeld und muss
121
+ // lesen, dass nichts hinausgegangen ist.
122
+ 'beleg.mail_nicht_gefunden': { text: 'Dieser Beleg wurde nicht gefunden — er konnte nicht gesendet werden.' },
78
123
  // --- Druck ---------------------------------------------------------------
79
124
  'druck.fehlgeschlagen': { text: 'Der Ausdruck ist fehlgeschlagen.' },
80
125
  'druck.nicht_moeglich': { text: 'Druck nicht möglich: {grund}', platzhalter: ['grund'] },
@@ -86,6 +131,22 @@ const MELDUNGEN_ROH = {
86
131
  'druck.kein_drucker_gefunden': { text: 'Kein Drucker gefunden — ist er eingeschaltet und im selben Netz wie dieser Rechner?', nur: ['web'] },
87
132
  'druck.nur_chrome': { text: '{weg}-Druck geht nur in Chrome oder Edge (Windows, Mac, Android) — nicht in Safari und nicht am iPad.', platzhalter: ['weg'], nur: ['web'] },
88
133
  'druck.kein_weg_drucker': { text: 'Kein {weg}-Drucker verbunden — „{weg}-Drucker verbinden“ und den Drucker im Dialog wählen.', platzhalter: ['weg'], nur: ['web'] },
134
+ // Der Drucker-Wizard: suchen, verbinden, Testdruck, QR-Probe, erst dann
135
+ // speichern. Derselbe Ablauf in beiden Kassen — deshalb hat kein Satz ein
136
+ // `nur`, obwohl der Weg zum Drucker verschieden ist (Bluetooth in der App,
137
+ // Web Bluetooth im Browser). Was der Chef liest, ist beidesmal dasselbe.
138
+ 'druck.wizard_verbinden': { text: 'Verbinde mit {name} …', platzhalter: ['name'] },
139
+ 'druck.wizard_testdruck_frage': { text: 'Ist der Testdruck gekommen?' },
140
+ 'druck.wizard_qr_frage': { text: 'Welcher QR-Code ist sauber gedruckt?' },
141
+ // Kein Modus druckt einen lesbaren QR-Code: gespeichert wird trotzdem (mit
142
+ // Raster als Vorgabe), aber der Chef muss wissen, dass der QR-Code dann vom
143
+ // Bildschirm gelesen werden muss — nach RKSV gehoert er an den Beleg.
144
+ 'druck.wizard_qr_keiner_hinweis': { text: 'Kein QR-Code kam sauber — der Beleg zeigt den QR-Code dann am Bildschirm.' },
145
+ 'druck.wizard_nichts_gekommen': { text: 'Nichts gekommen? Drucker an, Papier drin, richtiges Gerät gewählt?' },
146
+ 'druck.wizard_gespeichert': { text: '{name} ist eingerichtet.', platzhalter: ['name'] },
147
+ // Abbrechen an jeder Stelle: nichts gespeichert. Der Satz sagt genau das,
148
+ // damit niemand einen halb eingerichteten Drucker vermutet.
149
+ 'druck.wizard_abgebrochen': { text: 'Nichts gespeichert.' },
89
150
  'bluetooth.aus': { text: 'Bluetooth ist ausgeschaltet. Bitte einschalten und erneut suchen.', nur: ['app'] },
90
151
  'bluetooth.freigabe_fehlt': { text: 'Bitte die Freigabe in den Geräte-Einstellungen erteilen.', nur: ['app'] },
91
152
  'bluetooth.suche_fehlgeschlagen': { text: 'Die Suche ist fehlgeschlagen: {grund}', platzhalter: ['grund'], nur: ['app'] },
@@ -133,6 +194,39 @@ exports.FEHLERREGELN = [
133
194
  { art: 'unerwartet', schluessel: 'server.unerwartet' },
134
195
  { art: 'sonst', verhalten: 'ersatz' },
135
196
  ];
197
+ /**
198
+ * Beleg per E-Mail senden: welcher `code` des Backends welchen Satz bekommt.
199
+ *
200
+ * `FEHLERREGELN` bleibt davon unberuehrt — das hier ist keine neue Art, einen
201
+ * Transportfehler einzuordnen, sondern die Verfeinerung EINES Aufrufs
202
+ * (`sendReceiptEmail`). Die vier Ausgaenge sind fuer den Kassier vier
203
+ * verschiedene Handlungen: Adresse verbessern, spaeter noch einmal, noch
204
+ * einmal senden, Beleg suchen. Beide Kassen entscheiden am `code`, nicht am
205
+ * Satz des Backends — sonst haengt das Wort am Tresen an einer Formulierung,
206
+ * die sich im Backend jederzeit aendern darf.
207
+ *
208
+ * Bewusst ein Objekt und keine Liste in GROSSSCHRIFT: der
209
+ * Oberflaechen-Vertrag (`fixtures/oberflaeche.json`) liest jede exportierte
210
+ * Liste als Enum der Kasseneinstellungen ein, und der Dart-Zwilling schickt
211
+ * deren Werte durch `KasseSettings.aus`. Fehlercodes haben dort nichts
212
+ * verloren; sie stehen in `fixtures/kasse-texte.json`.
213
+ */
214
+ exports.BELEG_MAIL_FEHLER = {
215
+ adresse_ungueltig: 'beleg.mail_adresse_ungueltig',
216
+ zu_oft: 'beleg.mail_zu_oft',
217
+ versand_fehlgeschlagen: 'beleg.mail_fehlgeschlagen',
218
+ beleg_nicht_gefunden: 'beleg.mail_nicht_gefunden',
219
+ };
220
+ /**
221
+ * Der Satz zu einem `code` des Backends. Einen Code, den dieses Paket noch
222
+ * nicht kennt, faengt der allgemeine Satz auf: das Senden ist gescheitert und
223
+ * darf wiederholt werden. Ein leerer Schirm waere schlimmer als ein zu
224
+ * allgemeiner Satz.
225
+ */
226
+ function belegMailFehler(code) {
227
+ const fehler = exports.BELEG_MAIL_FEHLER;
228
+ return (code !== undefined && code !== null && fehler[code]) || 'beleg.mail_fehlgeschlagen';
229
+ }
136
230
  /** Der Satz zum Schluessel, Platzhalter ersetzt. Fehlt ein Wert, wirft es — ein `{status}` am Tresen waere schlimmer. */
137
231
  function meldung(schluessel, werte = {}) {
138
232
  const eintrag = exports.MELDUNGEN[schluessel];
@@ -10,4 +10,4 @@ export { verteileRabatt } from '../receipt/discount.js';
10
10
  export { cancelScopeOf, receiptsScopeOf, type RegisterScope, type RegisterUserPerms } from '../register/pairing.js';
11
11
  export { type NetzDrucker, type DruckJob, type DruckJobStatus, type CreatePrintJobOptions, listMyPrinters, createPrintJob, getPrintJob } from './drucker.js';
12
12
  export { listMyTipRecipients } from './trinkgeld.js';
13
- export { MELDUNGEN, FEHLERREGELN, meldung, meldungGiltFuer, type Meldung, type MeldungsSchluessel, type Fehlerart, type Seite, } from './texte.js';
13
+ export { MELDUNGEN, FEHLERREGELN, meldung, meldungGiltFuer, BELEG_MAIL_FEHLER, belegMailFehler, type Meldung, type MeldungsSchluessel, type Fehlerart, type Seite, type BelegMailFehlercode, } from './texte.js';
@@ -15,4 +15,4 @@ export { cancelScopeOf, receiptsScopeOf } from '../register/pairing.js';
15
15
  export { listMyPrinters, createPrintJob, getPrintJob } from './drucker.js';
16
16
  export { listMyTipRecipients } from './trinkgeld.js';
17
17
  // Was die Kasse selbst sagt — ein Katalog fuer Browser-Kasse und App.
18
- export { MELDUNGEN, FEHLERREGELN, meldung, meldungGiltFuer, } from './texte.js';
18
+ export { MELDUNGEN, FEHLERREGELN, meldung, meldungGiltFuer, BELEG_MAIL_FEHLER, belegMailFehler, } from './texte.js';
@@ -124,6 +124,17 @@ declare const MELDUNGEN_ROH: {
124
124
  readonly text: "Unklar, ob die Kartenzahlung durchgegangen ist — die Verbindung zum Terminal riss ab. Bitte am Terminal-Beleg nachsehen, BEVOR neu kassiert wird: die Karte kann belastet sein. Kennung der Zahlung: {kennung}.";
125
125
  readonly platzhalter: readonly ["kennung"];
126
126
  };
127
+ readonly 'kartenzahlung.wartet_auf_terminal': {
128
+ readonly text: "Bitte am Terminal fortfahren …";
129
+ };
130
+ readonly 'kartenzahlung.karte_gebucht_beleg_offen': {
131
+ readonly text: "Die Karte ist bereits mit {betrag} belastet (Kennung {kennung}) — der Beleg dazu fehlt noch. Bitte jetzt den Beleg erstellen und nicht erneut kassieren.";
132
+ readonly platzhalter: readonly ["betrag", "kennung"];
133
+ };
134
+ readonly 'kartenzahlung.karte_gebucht_korb_geaendert': {
135
+ readonly text: "Es gibt eine gebuchte Kartenzahlung über {betrag} (Kennung {kennung}), aber der Korb hat sich seither geändert. Bitte zuerst entscheiden: den Beleg zur gebuchten Zahlung erstellen oder die Zahlung am Terminal stornieren und hier verwerfen.";
136
+ readonly platzhalter: readonly ["betrag", "kennung"];
137
+ };
127
138
  readonly 'kartenzahlung.connect_nicht_verbunden': {
128
139
  readonly text: "Kartenzahlung nicht möglich: Kasseneck Connect ist nicht verbunden — Einstellungen → Kasseneck Connect.";
129
140
  readonly nur: readonly ["web"];
@@ -161,6 +172,34 @@ declare const MELDUNGEN_ROH: {
161
172
  readonly platzhalter: readonly ["code"];
162
173
  readonly nur: readonly ["app"];
163
174
  };
175
+ readonly 'gptom.abgelehnt': {
176
+ readonly text: "Das Terminal hat die Zahlung abgelehnt.";
177
+ readonly nur: readonly ["app"];
178
+ };
179
+ readonly 'gptom.abgelehnt_mit_code': {
180
+ readonly text: "Das Terminal hat die Zahlung abgelehnt ({code}).";
181
+ readonly platzhalter: readonly ["code"];
182
+ readonly nur: readonly ["app"];
183
+ };
184
+ readonly 'gptom.nicht_geoeffnet': {
185
+ readonly text: "GP Tom ließ sich nicht öffnen — bitte die GP-Tom-App prüfen und erneut versuchen.";
186
+ readonly nur: readonly ["app"];
187
+ };
188
+ readonly 'gptom.zeit_abgelaufen': {
189
+ readonly text: "Das Terminal hat in der Frist nicht geantwortet — die Karte kann belastet sein. Bitte am Terminal-Beleg nachsehen, BEVOR neu kassiert wird.";
190
+ readonly nur: readonly ["app"];
191
+ };
192
+ readonly 'gptom.zeit_abgelaufen_mit_kennung': {
193
+ readonly text: "Das Terminal hat in der Frist nicht geantwortet — die Karte kann belastet sein. Bitte am Terminal-Beleg nachsehen, BEVOR neu kassiert wird. Kennung der Zahlung: {kennung}.";
194
+ readonly platzhalter: readonly ["kennung"];
195
+ readonly nur: readonly ["app"];
196
+ };
197
+ readonly 'protokoll.leer': {
198
+ readonly text: "Noch keine Einträge — das Protokoll füllt sich mit der ersten Kartenzahlung.";
199
+ };
200
+ readonly 'protokoll.kopiert': {
201
+ readonly text: "Das Protokoll liegt in der Zwischenablage.";
202
+ };
164
203
  readonly 'belege.laden_fehlgeschlagen': {
165
204
  readonly text: "Die Belege konnten nicht geladen werden.";
166
205
  };
@@ -182,6 +221,35 @@ declare const MELDUNGEN_ROH: {
182
221
  readonly 'storno.position_fehlt': {
183
222
  readonly text: "Bitte mindestens eine Position wählen.";
184
223
  };
224
+ readonly 'beleg.link_kopiert': {
225
+ readonly text: "Der Link zum Beleg liegt in der Zwischenablage.";
226
+ };
227
+ readonly 'beleg.teilen_text': {
228
+ readonly text: "Beleg {nummer} von {betrieb} über {betrag}: {link}";
229
+ readonly platzhalter: readonly ["betrieb", "nummer", "betrag", "link"];
230
+ };
231
+ readonly 'beleg.nicht_teilbar': {
232
+ readonly text: "Für diesen Beleg gibt es keinen Link — er stammt aus einer älteren Kasse.";
233
+ };
234
+ readonly 'beleg.test_hinweis_teilen': {
235
+ readonly text: "Test-Umgebung — der Beleg ist steuerlich nicht gültig.";
236
+ };
237
+ readonly 'beleg.mail_gesendet': {
238
+ readonly text: "Der Beleg wurde an {an} gesendet.";
239
+ readonly platzhalter: readonly ["an"];
240
+ };
241
+ readonly 'beleg.mail_adresse_ungueltig': {
242
+ readonly text: "Diese E-Mail-Adresse ist nicht gültig.";
243
+ };
244
+ readonly 'beleg.mail_zu_oft': {
245
+ readonly text: "Dieser Beleg wurde schon oft gesendet — bitte später noch einmal.";
246
+ };
247
+ readonly 'beleg.mail_fehlgeschlagen': {
248
+ readonly text: "Der Beleg konnte nicht gesendet werden. Bitte noch einmal versuchen.";
249
+ };
250
+ readonly 'beleg.mail_nicht_gefunden': {
251
+ readonly text: "Dieser Beleg wurde nicht gefunden — er konnte nicht gesendet werden.";
252
+ };
185
253
  readonly 'druck.fehlgeschlagen': {
186
254
  readonly text: "Der Ausdruck ist fehlgeschlagen.";
187
255
  };
@@ -220,6 +288,29 @@ declare const MELDUNGEN_ROH: {
220
288
  readonly platzhalter: readonly ["weg"];
221
289
  readonly nur: readonly ["web"];
222
290
  };
291
+ readonly 'druck.wizard_verbinden': {
292
+ readonly text: "Verbinde mit {name} …";
293
+ readonly platzhalter: readonly ["name"];
294
+ };
295
+ readonly 'druck.wizard_testdruck_frage': {
296
+ readonly text: "Ist der Testdruck gekommen?";
297
+ };
298
+ readonly 'druck.wizard_qr_frage': {
299
+ readonly text: "Welcher QR-Code ist sauber gedruckt?";
300
+ };
301
+ readonly 'druck.wizard_qr_keiner_hinweis': {
302
+ readonly text: "Kein QR-Code kam sauber — der Beleg zeigt den QR-Code dann am Bildschirm.";
303
+ };
304
+ readonly 'druck.wizard_nichts_gekommen': {
305
+ readonly text: "Nichts gekommen? Drucker an, Papier drin, richtiges Gerät gewählt?";
306
+ };
307
+ readonly 'druck.wizard_gespeichert': {
308
+ readonly text: "{name} ist eingerichtet.";
309
+ readonly platzhalter: readonly ["name"];
310
+ };
311
+ readonly 'druck.wizard_abgebrochen': {
312
+ readonly text: "Nichts gespeichert.";
313
+ };
223
314
  readonly 'bluetooth.aus': {
224
315
  readonly text: "Bluetooth ist ausgeschaltet. Bitte einschalten und erneut suchen.";
225
316
  readonly nur: readonly ["app"];
@@ -329,6 +420,37 @@ export declare const FEHLERREGELN: readonly [{
329
420
  readonly verhalten: "ersatz";
330
421
  }];
331
422
  export type Fehlerart = (typeof FEHLERREGELN)[number]['art'];
423
+ /**
424
+ * Beleg per E-Mail senden: welcher `code` des Backends welchen Satz bekommt.
425
+ *
426
+ * `FEHLERREGELN` bleibt davon unberuehrt — das hier ist keine neue Art, einen
427
+ * Transportfehler einzuordnen, sondern die Verfeinerung EINES Aufrufs
428
+ * (`sendReceiptEmail`). Die vier Ausgaenge sind fuer den Kassier vier
429
+ * verschiedene Handlungen: Adresse verbessern, spaeter noch einmal, noch
430
+ * einmal senden, Beleg suchen. Beide Kassen entscheiden am `code`, nicht am
431
+ * Satz des Backends — sonst haengt das Wort am Tresen an einer Formulierung,
432
+ * die sich im Backend jederzeit aendern darf.
433
+ *
434
+ * Bewusst ein Objekt und keine Liste in GROSSSCHRIFT: der
435
+ * Oberflaechen-Vertrag (`fixtures/oberflaeche.json`) liest jede exportierte
436
+ * Liste als Enum der Kasseneinstellungen ein, und der Dart-Zwilling schickt
437
+ * deren Werte durch `KasseSettings.aus`. Fehlercodes haben dort nichts
438
+ * verloren; sie stehen in `fixtures/kasse-texte.json`.
439
+ */
440
+ export declare const BELEG_MAIL_FEHLER: {
441
+ readonly adresse_ungueltig: "beleg.mail_adresse_ungueltig";
442
+ readonly zu_oft: "beleg.mail_zu_oft";
443
+ readonly versand_fehlgeschlagen: "beleg.mail_fehlgeschlagen";
444
+ readonly beleg_nicht_gefunden: "beleg.mail_nicht_gefunden";
445
+ };
446
+ export type BelegMailFehlercode = keyof typeof BELEG_MAIL_FEHLER;
447
+ /**
448
+ * Der Satz zu einem `code` des Backends. Einen Code, den dieses Paket noch
449
+ * nicht kennt, faengt der allgemeine Satz auf: das Senden ist gescheitert und
450
+ * darf wiederholt werden. Ein leerer Schirm waere schlimmer als ein zu
451
+ * allgemeiner Satz.
452
+ */
453
+ export declare function belegMailFehler(code: string | undefined | null): MeldungsSchluessel;
332
454
  /** Der Satz zum Schluessel, Platzhalter ersetzt. Fehlt ein Wert, wirft es — ein `{status}` am Tresen waere schlimmer. */
333
455
  export declare function meldung(schluessel: MeldungsSchluessel, werte?: Record<string, string | number>): string;
334
456
  /** Gilt der Satz auf dieser Seite? */
@@ -54,6 +54,13 @@ const MELDUNGEN_ROH = {
54
54
  'kartenzahlung.unklar': { text: 'Unklar, ob die Kartenzahlung durchgegangen ist — die Verbindung zum Terminal riss ab. Bitte am Terminal-Beleg nachsehen, BEVOR neu kassiert wird: die Karte kann belastet sein.' },
55
55
  // Die Kennung ist der einzige Anker, um die Zahlung am Terminal-Beleg wiederzufinden — liegt sie vor, gilt dieser Satz statt kartenzahlung.unklar.
56
56
  'kartenzahlung.unklar_mit_kennung': { text: 'Unklar, ob die Kartenzahlung durchgegangen ist — die Verbindung zum Terminal riss ab. Bitte am Terminal-Beleg nachsehen, BEVOR neu kassiert wird: die Karte kann belastet sein. Kennung der Zahlung: {kennung}.', platzhalter: ['kennung'] },
57
+ 'kartenzahlung.wartet_auf_terminal': { text: 'Bitte am Terminal fortfahren …' },
58
+ // Ein geglücktes Kartenergebnis ohne Beleg ist der teuerste Zustand am Tresen:
59
+ // wer hier erneut kassiert, belastet die Karte ein zweites Mal. Beide Sätze
60
+ // nennen deshalb Betrag UND Kennung — nur damit findet der Kassier die Zahlung
61
+ // am Terminal-Beleg wieder — und keiner rät zum Wiederholen.
62
+ 'kartenzahlung.karte_gebucht_beleg_offen': { text: 'Die Karte ist bereits mit {betrag} belastet (Kennung {kennung}) — der Beleg dazu fehlt noch. Bitte jetzt den Beleg erstellen und nicht erneut kassieren.', platzhalter: ['betrag', 'kennung'] },
63
+ 'kartenzahlung.karte_gebucht_korb_geaendert': { text: 'Es gibt eine gebuchte Kartenzahlung über {betrag} (Kennung {kennung}), aber der Korb hat sich seither geändert. Bitte zuerst entscheiden: den Beleg zur gebuchten Zahlung erstellen oder die Zahlung am Terminal stornieren und hier verwerfen.', platzhalter: ['betrag', 'kennung'] },
57
64
  'kartenzahlung.connect_nicht_verbunden': { text: 'Kartenzahlung nicht möglich: Kasseneck Connect ist nicht verbunden — Einstellungen → Kasseneck Connect.', nur: ['web'] },
58
65
  'terminal.keines_gefunden': { text: 'Kein Hobex-Terminal gefunden — ist es eingeschaltet und im selben Netz wie dieser Rechner?', nur: ['web'] },
59
66
  'terminal.nicht_bereit': { text: 'Terminal antwortet, ist aber nicht betriebsbereit: {antwort} — TID prüfen.', platzhalter: ['antwort'], nur: ['web'] },
@@ -62,6 +69,19 @@ const MELDUNGEN_ROH = {
62
69
  'gptom.zahlung_fehlgeschlagen': { text: 'GP Tom: Zahlung fehlgeschlagen: {grund}', platzhalter: ['grund'], nur: ['app'] },
63
70
  'gptom.terminal_antwortet_nicht': { text: 'Das Terminal hat nicht geantwortet: {grund}', platzhalter: ['grund'], nur: ['app'] },
64
71
  'gptom.zahlung_nicht_abgeschlossen': { text: 'Die Zahlung wurde nicht abgeschlossen ({code}).', platzhalter: ['code'], nur: ['app'] },
72
+ // Abgelehnt heißt: das Terminal hat entschieden, es ist sicher nichts gebucht.
73
+ // Der Code ist die einzige Handhabe, mit der der Inhaber bei GP nachfragen kann —
74
+ // liegt einer vor, gilt die Fassung mit Code.
75
+ 'gptom.abgelehnt': { text: 'Das Terminal hat die Zahlung abgelehnt.', nur: ['app'] },
76
+ 'gptom.abgelehnt_mit_code': { text: 'Das Terminal hat die Zahlung abgelehnt ({code}).', platzhalter: ['code'], nur: ['app'] },
77
+ 'gptom.nicht_geoeffnet': { text: 'GP Tom ließ sich nicht öffnen — bitte die GP-Tom-App prüfen und erneut versuchen.', nur: ['app'] },
78
+ // Frist abgelaufen ist kein Abbruch: die Karte kann belastet sein, nur die
79
+ // Antwort blieb aus. Deshalb derselbe Ton wie kartenzahlung.unklar.
80
+ 'gptom.zeit_abgelaufen': { text: 'Das Terminal hat in der Frist nicht geantwortet — die Karte kann belastet sein. Bitte am Terminal-Beleg nachsehen, BEVOR neu kassiert wird.', nur: ['app'] },
81
+ 'gptom.zeit_abgelaufen_mit_kennung': { text: 'Das Terminal hat in der Frist nicht geantwortet — die Karte kann belastet sein. Bitte am Terminal-Beleg nachsehen, BEVOR neu kassiert wird. Kennung der Zahlung: {kennung}.', platzhalter: ['kennung'], nur: ['app'] },
82
+ // --- Terminal-Protokoll --------------------------------------------------
83
+ 'protokoll.leer': { text: 'Noch keine Einträge — das Protokoll füllt sich mit der ersten Kartenzahlung.' },
84
+ 'protokoll.kopiert': { text: 'Das Protokoll liegt in der Zwischenablage.' },
65
85
  // --- Belege und Storno ---------------------------------------------------
66
86
  'belege.laden_fehlgeschlagen': { text: 'Die Belege konnten nicht geladen werden.' },
67
87
  'belege.keine_im_zeitraum': { text: 'Keine Belege in diesem Zeitraum.' },
@@ -70,6 +90,30 @@ const MELDUNGEN_ROH = {
70
90
  'storno.fehlgeschlagen': { text: 'Das Storno ist fehlgeschlagen.' },
71
91
  'storno.grund_fehlt': { text: 'Bitte einen Grund wählen.' },
72
92
  'storno.position_fehlt': { text: 'Bitte mindestens eine Position wählen.' },
93
+ // --- Beleg weitergeben: Link, Teilen, E-Mail -----------------------------
94
+ // Kopieren, Teilen und Senden fuehren zu demselben Ziel: der oeffentlichen
95
+ // Belegseite (beleg.kasseneck.at/<fullReceiptId>). Kein Satz davon ist
96
+ // plattformgebunden — nur die Huelle unterscheidet sich, nicht das Wort.
97
+ 'beleg.link_kopiert': { text: 'Der Link zum Beleg liegt in der Zwischenablage.' },
98
+ // Der Text, der beim Teilen mitgeht. Der Link steht am Schluss, damit ihn
99
+ // jede Huelle (SMS, Messenger, Mail) bis zum Ende als Link erkennt und nicht
100
+ // mitten im Satz abbricht.
101
+ 'beleg.teilen_text': { text: 'Beleg {nummer} von {betrieb} über {betrag}: {link}', platzhalter: ['betrieb', 'nummer', 'betrag', 'link'] },
102
+ // Belege aus dem Altbestand tragen keine `fullReceiptId`; ohne sie gibt es
103
+ // keine Belegseite. Der Satz nennt den Grund, sonst sucht der Kassier den
104
+ // Fehler bei sich und versucht es ein zweites Mal.
105
+ 'beleg.nicht_teilbar': { text: 'Für diesen Beleg gibt es keinen Link — er stammt aus einer älteren Kasse.' },
106
+ // Ein Testbeleg hat eine Belegseite, ist aber steuerlich nichts wert. Wer
107
+ // den Link weitergibt, muss das vorher lesen, nicht hinterher.
108
+ 'beleg.test_hinweis_teilen': { text: 'Test-Umgebung — der Beleg ist steuerlich nicht gültig.' },
109
+ 'beleg.mail_gesendet': { text: 'Der Beleg wurde an {an} gesendet.', platzhalter: ['an'] },
110
+ 'beleg.mail_adresse_ungueltig': { text: 'Diese E-Mail-Adresse ist nicht gültig.' },
111
+ 'beleg.mail_zu_oft': { text: 'Dieser Beleg wurde schon oft gesendet — bitte später noch einmal.' },
112
+ 'beleg.mail_fehlgeschlagen': { text: 'Der Beleg konnte nicht gesendet werden. Bitte noch einmal versuchen.' },
113
+ // Bewusst nicht derselbe Satz wie `beleg.nicht_gefunden`: dort scheitert das
114
+ // Oeffnen, hier das Senden. Der Kassier steht vor einem Adressfeld und muss
115
+ // lesen, dass nichts hinausgegangen ist.
116
+ 'beleg.mail_nicht_gefunden': { text: 'Dieser Beleg wurde nicht gefunden — er konnte nicht gesendet werden.' },
73
117
  // --- Druck ---------------------------------------------------------------
74
118
  'druck.fehlgeschlagen': { text: 'Der Ausdruck ist fehlgeschlagen.' },
75
119
  'druck.nicht_moeglich': { text: 'Druck nicht möglich: {grund}', platzhalter: ['grund'] },
@@ -81,6 +125,22 @@ const MELDUNGEN_ROH = {
81
125
  'druck.kein_drucker_gefunden': { text: 'Kein Drucker gefunden — ist er eingeschaltet und im selben Netz wie dieser Rechner?', nur: ['web'] },
82
126
  'druck.nur_chrome': { text: '{weg}-Druck geht nur in Chrome oder Edge (Windows, Mac, Android) — nicht in Safari und nicht am iPad.', platzhalter: ['weg'], nur: ['web'] },
83
127
  'druck.kein_weg_drucker': { text: 'Kein {weg}-Drucker verbunden — „{weg}-Drucker verbinden“ und den Drucker im Dialog wählen.', platzhalter: ['weg'], nur: ['web'] },
128
+ // Der Drucker-Wizard: suchen, verbinden, Testdruck, QR-Probe, erst dann
129
+ // speichern. Derselbe Ablauf in beiden Kassen — deshalb hat kein Satz ein
130
+ // `nur`, obwohl der Weg zum Drucker verschieden ist (Bluetooth in der App,
131
+ // Web Bluetooth im Browser). Was der Chef liest, ist beidesmal dasselbe.
132
+ 'druck.wizard_verbinden': { text: 'Verbinde mit {name} …', platzhalter: ['name'] },
133
+ 'druck.wizard_testdruck_frage': { text: 'Ist der Testdruck gekommen?' },
134
+ 'druck.wizard_qr_frage': { text: 'Welcher QR-Code ist sauber gedruckt?' },
135
+ // Kein Modus druckt einen lesbaren QR-Code: gespeichert wird trotzdem (mit
136
+ // Raster als Vorgabe), aber der Chef muss wissen, dass der QR-Code dann vom
137
+ // Bildschirm gelesen werden muss — nach RKSV gehoert er an den Beleg.
138
+ 'druck.wizard_qr_keiner_hinweis': { text: 'Kein QR-Code kam sauber — der Beleg zeigt den QR-Code dann am Bildschirm.' },
139
+ 'druck.wizard_nichts_gekommen': { text: 'Nichts gekommen? Drucker an, Papier drin, richtiges Gerät gewählt?' },
140
+ 'druck.wizard_gespeichert': { text: '{name} ist eingerichtet.', platzhalter: ['name'] },
141
+ // Abbrechen an jeder Stelle: nichts gespeichert. Der Satz sagt genau das,
142
+ // damit niemand einen halb eingerichteten Drucker vermutet.
143
+ 'druck.wizard_abgebrochen': { text: 'Nichts gespeichert.' },
84
144
  'bluetooth.aus': { text: 'Bluetooth ist ausgeschaltet. Bitte einschalten und erneut suchen.', nur: ['app'] },
85
145
  'bluetooth.freigabe_fehlt': { text: 'Bitte die Freigabe in den Geräte-Einstellungen erteilen.', nur: ['app'] },
86
146
  'bluetooth.suche_fehlgeschlagen': { text: 'Die Suche ist fehlgeschlagen: {grund}', platzhalter: ['grund'], nur: ['app'] },
@@ -128,6 +188,39 @@ export const FEHLERREGELN = [
128
188
  { art: 'unerwartet', schluessel: 'server.unerwartet' },
129
189
  { art: 'sonst', verhalten: 'ersatz' },
130
190
  ];
191
+ /**
192
+ * Beleg per E-Mail senden: welcher `code` des Backends welchen Satz bekommt.
193
+ *
194
+ * `FEHLERREGELN` bleibt davon unberuehrt — das hier ist keine neue Art, einen
195
+ * Transportfehler einzuordnen, sondern die Verfeinerung EINES Aufrufs
196
+ * (`sendReceiptEmail`). Die vier Ausgaenge sind fuer den Kassier vier
197
+ * verschiedene Handlungen: Adresse verbessern, spaeter noch einmal, noch
198
+ * einmal senden, Beleg suchen. Beide Kassen entscheiden am `code`, nicht am
199
+ * Satz des Backends — sonst haengt das Wort am Tresen an einer Formulierung,
200
+ * die sich im Backend jederzeit aendern darf.
201
+ *
202
+ * Bewusst ein Objekt und keine Liste in GROSSSCHRIFT: der
203
+ * Oberflaechen-Vertrag (`fixtures/oberflaeche.json`) liest jede exportierte
204
+ * Liste als Enum der Kasseneinstellungen ein, und der Dart-Zwilling schickt
205
+ * deren Werte durch `KasseSettings.aus`. Fehlercodes haben dort nichts
206
+ * verloren; sie stehen in `fixtures/kasse-texte.json`.
207
+ */
208
+ export const BELEG_MAIL_FEHLER = {
209
+ adresse_ungueltig: 'beleg.mail_adresse_ungueltig',
210
+ zu_oft: 'beleg.mail_zu_oft',
211
+ versand_fehlgeschlagen: 'beleg.mail_fehlgeschlagen',
212
+ beleg_nicht_gefunden: 'beleg.mail_nicht_gefunden',
213
+ };
214
+ /**
215
+ * Der Satz zu einem `code` des Backends. Einen Code, den dieses Paket noch
216
+ * nicht kennt, faengt der allgemeine Satz auf: das Senden ist gescheitert und
217
+ * darf wiederholt werden. Ein leerer Schirm waere schlimmer als ein zu
218
+ * allgemeiner Satz.
219
+ */
220
+ export function belegMailFehler(code) {
221
+ const fehler = BELEG_MAIL_FEHLER;
222
+ return (code !== undefined && code !== null && fehler[code]) || 'beleg.mail_fehlgeschlagen';
223
+ }
131
224
  /** Der Satz zum Schluessel, Platzhalter ersetzt. Fehlt ein Wert, wirft es — ein `{status}` am Tresen waere schlimmer. */
132
225
  export function meldung(schluessel, werte = {}) {
133
226
  const eintrag = MELDUNGEN[schluessel];
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.9.0",
2
+ "version": "0.9.2",
3
3
  "gemessenAn": {
4
4
  "tid": "3600335",
5
5
  "hpsVersion": "1.10.0",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.9.0",
2
+ "version": "0.9.2",
3
3
  "meldungen": {
4
4
  "netz.keine_verbindung": {
5
5
  "text": "Keine Verbindung zum Server. Bitte die Internetverbindung prüfen und erneut versuchen."
@@ -112,6 +112,23 @@
112
112
  "kennung"
113
113
  ]
114
114
  },
115
+ "kartenzahlung.wartet_auf_terminal": {
116
+ "text": "Bitte am Terminal fortfahren …"
117
+ },
118
+ "kartenzahlung.karte_gebucht_beleg_offen": {
119
+ "text": "Die Karte ist bereits mit {betrag} belastet (Kennung {kennung}) — der Beleg dazu fehlt noch. Bitte jetzt den Beleg erstellen und nicht erneut kassieren.",
120
+ "platzhalter": [
121
+ "betrag",
122
+ "kennung"
123
+ ]
124
+ },
125
+ "kartenzahlung.karte_gebucht_korb_geaendert": {
126
+ "text": "Es gibt eine gebuchte Kartenzahlung über {betrag} (Kennung {kennung}), aber der Korb hat sich seither geändert. Bitte zuerst entscheiden: den Beleg zur gebuchten Zahlung erstellen oder die Zahlung am Terminal stornieren und hier verwerfen.",
127
+ "platzhalter": [
128
+ "betrag",
129
+ "kennung"
130
+ ]
131
+ },
115
132
  "kartenzahlung.connect_nicht_verbunden": {
116
133
  "text": "Kartenzahlung nicht möglich: Kasseneck Connect ist nicht verbunden — Einstellungen → Kasseneck Connect.",
117
134
  "nur": [
@@ -175,6 +192,48 @@
175
192
  "app"
176
193
  ]
177
194
  },
195
+ "gptom.abgelehnt": {
196
+ "text": "Das Terminal hat die Zahlung abgelehnt.",
197
+ "nur": [
198
+ "app"
199
+ ]
200
+ },
201
+ "gptom.abgelehnt_mit_code": {
202
+ "text": "Das Terminal hat die Zahlung abgelehnt ({code}).",
203
+ "platzhalter": [
204
+ "code"
205
+ ],
206
+ "nur": [
207
+ "app"
208
+ ]
209
+ },
210
+ "gptom.nicht_geoeffnet": {
211
+ "text": "GP Tom ließ sich nicht öffnen — bitte die GP-Tom-App prüfen und erneut versuchen.",
212
+ "nur": [
213
+ "app"
214
+ ]
215
+ },
216
+ "gptom.zeit_abgelaufen": {
217
+ "text": "Das Terminal hat in der Frist nicht geantwortet — die Karte kann belastet sein. Bitte am Terminal-Beleg nachsehen, BEVOR neu kassiert wird.",
218
+ "nur": [
219
+ "app"
220
+ ]
221
+ },
222
+ "gptom.zeit_abgelaufen_mit_kennung": {
223
+ "text": "Das Terminal hat in der Frist nicht geantwortet — die Karte kann belastet sein. Bitte am Terminal-Beleg nachsehen, BEVOR neu kassiert wird. Kennung der Zahlung: {kennung}.",
224
+ "platzhalter": [
225
+ "kennung"
226
+ ],
227
+ "nur": [
228
+ "app"
229
+ ]
230
+ },
231
+ "protokoll.leer": {
232
+ "text": "Noch keine Einträge — das Protokoll füllt sich mit der ersten Kartenzahlung."
233
+ },
234
+ "protokoll.kopiert": {
235
+ "text": "Das Protokoll liegt in der Zwischenablage."
236
+ },
178
237
  "belege.laden_fehlgeschlagen": {
179
238
  "text": "Die Belege konnten nicht geladen werden."
180
239
  },
@@ -196,6 +255,42 @@
196
255
  "storno.position_fehlt": {
197
256
  "text": "Bitte mindestens eine Position wählen."
198
257
  },
258
+ "beleg.link_kopiert": {
259
+ "text": "Der Link zum Beleg liegt in der Zwischenablage."
260
+ },
261
+ "beleg.teilen_text": {
262
+ "text": "Beleg {nummer} von {betrieb} über {betrag}: {link}",
263
+ "platzhalter": [
264
+ "betrieb",
265
+ "nummer",
266
+ "betrag",
267
+ "link"
268
+ ]
269
+ },
270
+ "beleg.nicht_teilbar": {
271
+ "text": "Für diesen Beleg gibt es keinen Link — er stammt aus einer älteren Kasse."
272
+ },
273
+ "beleg.test_hinweis_teilen": {
274
+ "text": "Test-Umgebung — der Beleg ist steuerlich nicht gültig."
275
+ },
276
+ "beleg.mail_gesendet": {
277
+ "text": "Der Beleg wurde an {an} gesendet.",
278
+ "platzhalter": [
279
+ "an"
280
+ ]
281
+ },
282
+ "beleg.mail_adresse_ungueltig": {
283
+ "text": "Diese E-Mail-Adresse ist nicht gültig."
284
+ },
285
+ "beleg.mail_zu_oft": {
286
+ "text": "Dieser Beleg wurde schon oft gesendet — bitte später noch einmal."
287
+ },
288
+ "beleg.mail_fehlgeschlagen": {
289
+ "text": "Der Beleg konnte nicht gesendet werden. Bitte noch einmal versuchen."
290
+ },
291
+ "beleg.mail_nicht_gefunden": {
292
+ "text": "Dieser Beleg wurde nicht gefunden — er konnte nicht gesendet werden."
293
+ },
199
294
  "druck.fehlgeschlagen": {
200
295
  "text": "Der Ausdruck ist fehlgeschlagen."
201
296
  },
@@ -250,6 +345,33 @@
250
345
  "web"
251
346
  ]
252
347
  },
348
+ "druck.wizard_verbinden": {
349
+ "text": "Verbinde mit {name} …",
350
+ "platzhalter": [
351
+ "name"
352
+ ]
353
+ },
354
+ "druck.wizard_testdruck_frage": {
355
+ "text": "Ist der Testdruck gekommen?"
356
+ },
357
+ "druck.wizard_qr_frage": {
358
+ "text": "Welcher QR-Code ist sauber gedruckt?"
359
+ },
360
+ "druck.wizard_qr_keiner_hinweis": {
361
+ "text": "Kein QR-Code kam sauber — der Beleg zeigt den QR-Code dann am Bildschirm."
362
+ },
363
+ "druck.wizard_nichts_gekommen": {
364
+ "text": "Nichts gekommen? Drucker an, Papier drin, richtiges Gerät gewählt?"
365
+ },
366
+ "druck.wizard_gespeichert": {
367
+ "text": "{name} ist eingerichtet.",
368
+ "platzhalter": [
369
+ "name"
370
+ ]
371
+ },
372
+ "druck.wizard_abgebrochen": {
373
+ "text": "Nichts gespeichert."
374
+ },
253
375
  "bluetooth.aus": {
254
376
  "text": "Bluetooth ist ausgeschaltet. Bitte einschalten und erneut suchen.",
255
377
  "nur": [
@@ -381,5 +503,11 @@
381
503
  "art": "sonst",
382
504
  "verhalten": "ersatz"
383
505
  }
384
- ]
506
+ ],
507
+ "belegMailFehler": {
508
+ "adresse_ungueltig": "beleg.mail_adresse_ungueltig",
509
+ "zu_oft": "beleg.mail_zu_oft",
510
+ "versand_fehlgeschlagen": "beleg.mail_fehlgeschlagen",
511
+ "beleg_nicht_gefunden": "beleg.mail_nicht_gefunden"
512
+ }
385
513
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.9.0",
2
+ "version": "0.9.2",
3
3
  "aufrufe": [
4
4
  "activateCashregister",
5
5
  "cancelReceipt",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kreiseck/kasseneck-api",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "JavaScript-Zwilling von kasseneck_api (Flutter) fuer das Kasseneck-Backend",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Kreiseck",