@kreiseck/kasseneck-api 0.29.0 → 0.31.0

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.
Files changed (119) hide show
  1. package/CHANGELOG.md +174 -0
  2. package/dist/cjs/client/api.d.ts +3 -3
  3. package/dist/cjs/client/index.d.ts +1 -1
  4. package/dist/cjs/client/receipts.d.ts +32 -3
  5. package/dist/cjs/client/receipts.js +121 -6
  6. package/dist/cjs/enums/keck-payment-method.d.ts +10 -0
  7. package/dist/cjs/enums/keck-payment-method.js +6 -0
  8. package/dist/cjs/index.d.ts +2 -2
  9. package/dist/cjs/index.js +6 -2
  10. package/dist/cjs/kasse/index.d.ts +1 -1
  11. package/dist/cjs/kasse/index.js +5 -1
  12. package/dist/cjs/kasse/settings.d.ts +4 -2
  13. package/dist/cjs/kasse/settings.js +5 -2
  14. package/dist/cjs/kasse/texte.d.ts +444 -34
  15. package/dist/cjs/kasse/texte.js +265 -35
  16. package/dist/cjs/models/cancellation.d.ts +25 -2
  17. package/dist/cjs/models/cancellation.js +20 -1
  18. package/dist/cjs/models/index.d.ts +2 -0
  19. package/dist/cjs/models/index.js +7 -1
  20. package/dist/cjs/models/payment-errors.d.ts +22 -0
  21. package/dist/cjs/models/payment-errors.js +46 -0
  22. package/dist/cjs/models/receipt-payment.d.ts +86 -0
  23. package/dist/cjs/models/receipt-payment.js +40 -0
  24. package/dist/cjs/models/receipt-summary.d.ts +9 -0
  25. package/dist/cjs/models/receipt-summary.js +2 -0
  26. package/dist/cjs/models/receipt.d.ts +9 -0
  27. package/dist/cjs/models/receipt.js +19 -0
  28. package/dist/cjs/payments/hobex-hps/transaction-response.js +28 -28
  29. package/dist/cjs/receipt/layout.js +112 -10
  30. package/dist/esm/client/api.d.ts +3 -3
  31. package/dist/esm/client/index.d.ts +1 -1
  32. package/dist/esm/client/receipts.d.ts +32 -3
  33. package/dist/esm/client/receipts.js +121 -6
  34. package/dist/esm/enums/keck-payment-method.d.ts +10 -0
  35. package/dist/esm/enums/keck-payment-method.js +6 -0
  36. package/dist/esm/index.d.ts +2 -2
  37. package/dist/esm/index.js +1 -1
  38. package/dist/esm/kasse/index.d.ts +1 -1
  39. package/dist/esm/kasse/index.js +1 -1
  40. package/dist/esm/kasse/settings.d.ts +4 -2
  41. package/dist/esm/kasse/settings.js +5 -2
  42. package/dist/esm/kasse/texte.d.ts +444 -34
  43. package/dist/esm/kasse/texte.js +262 -34
  44. package/dist/esm/models/cancellation.d.ts +25 -2
  45. package/dist/esm/models/cancellation.js +20 -1
  46. package/dist/esm/models/index.d.ts +2 -0
  47. package/dist/esm/models/index.js +2 -0
  48. package/dist/esm/models/payment-errors.d.ts +22 -0
  49. package/dist/esm/models/payment-errors.js +42 -0
  50. package/dist/esm/models/receipt-payment.d.ts +86 -0
  51. package/dist/esm/models/receipt-payment.js +36 -0
  52. package/dist/esm/models/receipt-summary.d.ts +9 -0
  53. package/dist/esm/models/receipt-summary.js +2 -0
  54. package/dist/esm/models/receipt.d.ts +9 -0
  55. package/dist/esm/models/receipt.js +19 -0
  56. package/dist/esm/payments/hobex-hps/transaction-response.js +28 -28
  57. package/dist/esm/receipt/layout.js +112 -10
  58. package/fixtures/belege/split-bar-rueckgeld.json +58 -0
  59. package/fixtures/belege/split-eine-karte-trinkgeld.json +75 -0
  60. package/fixtures/belege/split-karte-karte-bar.json +102 -0
  61. package/fixtures/belege/split-langer-betrag.json +74 -0
  62. package/fixtures/belege/split-tischrunde-trinkgeld.json +152 -0
  63. package/fixtures/belege/split-trinkgeld-karte.json +82 -0
  64. package/fixtures/belege/split-zwei-karten-gleicher-anbieter.json +89 -0
  65. package/fixtures/belege/storno-split-teil.json +71 -0
  66. package/fixtures/belege/storno-split-voll.json +100 -0
  67. package/fixtures/erwartet/split-bar-rueckgeld.blatt32.json +194 -0
  68. package/fixtures/erwartet/split-bar-rueckgeld.blatt48.json +182 -0
  69. package/fixtures/erwartet/split-bar-rueckgeld.grid32.txt +28 -0
  70. package/fixtures/erwartet/split-bar-rueckgeld.grid48.txt +26 -0
  71. package/fixtures/erwartet/split-bar-rueckgeld.lines.json +286 -0
  72. package/fixtures/erwartet/split-eine-karte-trinkgeld.blatt32.json +242 -0
  73. package/fixtures/erwartet/split-eine-karte-trinkgeld.blatt48.json +224 -0
  74. package/fixtures/erwartet/split-eine-karte-trinkgeld.grid32.txt +36 -0
  75. package/fixtures/erwartet/split-eine-karte-trinkgeld.grid48.txt +33 -0
  76. package/fixtures/erwartet/split-eine-karte-trinkgeld.lines.json +371 -0
  77. package/fixtures/erwartet/split-karte-karte-bar.blatt32.json +356 -0
  78. package/fixtures/erwartet/split-karte-karte-bar.blatt48.json +338 -0
  79. package/fixtures/erwartet/split-karte-karte-bar.grid32.txt +55 -0
  80. package/fixtures/erwartet/split-karte-karte-bar.grid48.txt +52 -0
  81. package/fixtures/erwartet/split-karte-karte-bar.lines.json +519 -0
  82. package/fixtures/erwartet/split-langer-betrag.blatt32.json +266 -0
  83. package/fixtures/erwartet/split-langer-betrag.blatt48.json +260 -0
  84. package/fixtures/erwartet/split-langer-betrag.grid32.txt +40 -0
  85. package/fixtures/erwartet/split-langer-betrag.grid48.txt +39 -0
  86. package/fixtures/erwartet/split-langer-betrag.lines.json +343 -0
  87. package/fixtures/erwartet/split-tischrunde-trinkgeld.blatt32.json +470 -0
  88. package/fixtures/erwartet/split-tischrunde-trinkgeld.blatt48.json +434 -0
  89. package/fixtures/erwartet/split-tischrunde-trinkgeld.grid32.txt +74 -0
  90. package/fixtures/erwartet/split-tischrunde-trinkgeld.grid48.txt +68 -0
  91. package/fixtures/erwartet/split-tischrunde-trinkgeld.lines.json +740 -0
  92. package/fixtures/erwartet/split-trinkgeld-karte.blatt32.json +272 -0
  93. package/fixtures/erwartet/split-trinkgeld-karte.blatt48.json +254 -0
  94. package/fixtures/erwartet/split-trinkgeld-karte.grid32.txt +41 -0
  95. package/fixtures/erwartet/split-trinkgeld-karte.grid48.txt +38 -0
  96. package/fixtures/erwartet/split-trinkgeld-karte.lines.json +428 -0
  97. package/fixtures/erwartet/split-zwei-karten-gleicher-anbieter.blatt32.json +326 -0
  98. package/fixtures/erwartet/split-zwei-karten-gleicher-anbieter.blatt48.json +296 -0
  99. package/fixtures/erwartet/split-zwei-karten-gleicher-anbieter.grid32.txt +50 -0
  100. package/fixtures/erwartet/split-zwei-karten-gleicher-anbieter.grid48.txt +45 -0
  101. package/fixtures/erwartet/split-zwei-karten-gleicher-anbieter.lines.json +504 -0
  102. package/fixtures/erwartet/storno-split-teil.blatt32.json +230 -0
  103. package/fixtures/erwartet/storno-split-teil.blatt48.json +224 -0
  104. package/fixtures/erwartet/storno-split-teil.grid32.txt +34 -0
  105. package/fixtures/erwartet/storno-split-teil.grid48.txt +33 -0
  106. package/fixtures/erwartet/storno-split-teil.lines.json +304 -0
  107. package/fixtures/erwartet/storno-split-voll.blatt32.json +320 -0
  108. package/fixtures/erwartet/storno-split-voll.blatt48.json +314 -0
  109. package/fixtures/erwartet/storno-split-voll.grid32.txt +49 -0
  110. package/fixtures/erwartet/storno-split-voll.grid48.txt +48 -0
  111. package/fixtures/erwartet/storno-split-voll.lines.json +410 -0
  112. package/fixtures/hobex-hps-codes.json +29 -29
  113. package/fixtures/kasse-settings-standard.json +4 -2
  114. package/fixtures/kasse-texte.json +479 -35
  115. package/fixtures/manifest.json +72 -0
  116. package/fixtures/oberflaeche.json +3 -2
  117. package/fixtures/rechnung-api.schema.json +1 -1
  118. package/fixtures/rechnung-texte.json +1 -1
  119. package/package.json +1 -1
@@ -23,16 +23,22 @@ const MELDUNGEN_ROH = {
23
23
  'kopplung.code_fehlt': { text: 'Bitte den Kopplungs-Code eingeben.' },
24
24
  'kopplung.fehlgeschlagen': { text: 'Die Kopplung ist fehlgeschlagen. Bitte erneut versuchen.' },
25
25
  'kopplung.unvollstaendig': { text: 'Die Kopplung ist unvollständig zurückgekommen. Bitte im Panel einen neuen Code erzeugen und noch einmal versuchen.' },
26
- 'geraet.browser_speicher': { text: 'Dieses Gerät konnte nicht gespeichert werden — der Browser-Speicher steht nicht zur Verfügung. Bitte den privaten Modus verlassen.', nur: ['web'] },
26
+ 'geraet.browser_speicher': { text: 'Dieses Gerät konnte nicht gespeichert werden – der Browser-Speicher steht nicht zur Verfügung. Bitte den privaten Modus verlassen.', nur: ['web'] },
27
27
  // --- Anmeldung und Sitzung -----------------------------------------------
28
28
  'anmeldung.pin_fehlt': { text: 'Bitte die PIN eingeben.' },
29
29
  'anmeldung.fehlgeschlagen': { text: 'Die Anmeldung ist fehlgeschlagen. Bitte erneut versuchen.' },
30
30
  'anmeldung.nicht_abgeschlossen': { text: 'Die Anmeldung konnte nicht abgeschlossen werden. Bitte erneut versuchen.' },
31
- 'anmeldung.wird_abgeschlossen': { text: 'Anmeldung wird gerade abgeschlossen — bitte gleich noch einmal drücken.' },
31
+ 'anmeldung.wird_abgeschlossen': { text: 'Anmeldung wird gerade abgeschlossen – bitte gleich noch einmal drücken.' },
32
32
  'sitzung.abgelaufen': { text: 'Die Sitzung ist abgelaufen. Bitte erneut anmelden.' },
33
- 'sitzung.abgelaufen_ohne_netz': { text: 'Keine Verbindung zum Server — die Sitzung ist abgelaufen. Bitte erneut anmelden.' },
33
+ 'sitzung.abgelaufen_ohne_netz': { text: 'Keine Verbindung zum Server – die Sitzung ist abgelaufen. Bitte erneut anmelden.' },
34
34
  'sitzung.keine': { text: 'Keine Sitzung.' },
35
- 'rechte.nicht_aenderbar': { text: 'Das darfst du nicht ändern — das Recht dafür vergibt der Inhaber im Panel.' },
35
+ // Die Sperre nach Untaetigkeit kuendigt sich an: der Countdown laeuft in
36
+ // Sekunden, eine Beruehrung haelt die Schicht offen.
37
+ 'sitzung.meldet_ab': { text: 'Kasse meldet in {sekunden} s ab – Bildschirm berühren, um weiterzuarbeiten.', platzhalter: ['sekunden'] },
38
+ // Wer die Abmelden-Taste ein zweites Mal drueckt, beendet die Schicht –
39
+ // der Satz steht in der Rueckfrage, bevor es so weit ist.
40
+ 'abmelden.noch_einmal': { text: 'Noch einmal drücken beendet die Schicht an dieser Kasse.' },
41
+ 'rechte.nicht_aenderbar': { text: 'Das darfst du nicht ändern – das Recht dafür vergibt der Inhaber im Panel.' },
36
42
  // --- Verkauf und Positionen ----------------------------------------------
37
43
  'kasse.laden_fehlgeschlagen': { text: 'Die Kasse konnte nicht geladen werden.' },
38
44
  'artikel.laden_fehlgeschlagen': { text: 'Die Artikel konnten nicht geladen werden.' },
@@ -40,30 +46,53 @@ const MELDUNGEN_ROH = {
40
46
  'artikel.keine_gefunden': { text: 'Keine Artikel gefunden.' },
41
47
  'artikel.steuersatz_unbekannt': { text: '„{name}“ hat einen Steuersatz, den die Kasse nicht kennt.', platzhalter: ['name'] },
42
48
  'position.betrag_fehlt': { text: 'Bitte einen Betrag eingeben.' },
43
- 'position.bezeichnung_fehlt': { text: 'Bitte eine Bezeichnung eingeben — sie steht am Beleg.' },
49
+ 'position.bezeichnung_fehlt': { text: 'Bitte eine Bezeichnung eingeben – sie steht am Beleg.' },
44
50
  'rabatt.prozent_ungueltig': { text: 'Bitte einen Prozentwert zwischen 0,1 und 100 eingeben.' },
51
+ // --- Kassieren -----------------------------------------------------------
52
+ // Der Grund ueber dem Knopf, solange der Beleg nicht abgeschlossen werden kann.
53
+ 'kassieren.nichts_erfasst': { text: 'Noch nichts erfasst – bitte zuerst eine Position aufnehmen.' },
54
+ 'kassieren.gegeben_fehlt': { text: 'Erst eintippen, was der Gast gibt – der Rückgeld-Rechner ist an.' },
55
+ 'kassieren.gegeben_zu_wenig': { text: 'Gegeben ist weniger als der Betrag.' },
56
+ // Lebenszyklus der Kasse (ausser Betrieb, Signatureinheit …): der Grund
57
+ // kommt vom Server bzw. aus dem Kassenstand und steht hinter dem Doppelpunkt.
58
+ 'kassieren.gesperrt': { text: 'Kassieren gesperrt: {grund}', platzhalter: ['grund'] },
59
+ // Keine gesetzliche Obergrenze – steuerfrei ist aber nur ortsuebliches
60
+ // Trinkgeld (§ 3 Abs 1 Z 16a EStG). Eine Warnung, keine Sperre.
61
+ 'trinkgeld.ueber_haelfte': { text: 'Über 50 % Trinkgeld – wirklich? Steuerfrei ist nur ortsübliches Trinkgeld.' },
45
62
  // --- Abschluss -----------------------------------------------------------
46
63
  'abschluss.fehlgeschlagen': { text: 'Der Abschluss ist fehlgeschlagen.' },
47
- 'abschluss.unklar': { text: 'Unklar, ob der Beleg entstanden ist — die Antwort kam nicht an. Bitte nicht noch einmal abschließen: der Beleg kann bereits erstellt und signiert sein. Im Panel unter „Belege“ nachsehen; nur wenn er dort fehlt, den Verkauf erneut abschließen.' },
64
+ 'abschluss.unklar': { text: 'Unklar, ob der Beleg entstanden ist – die Antwort kam nicht an. Bitte nicht noch einmal abschließen: der Beleg kann bereits erstellt und signiert sein. Im Panel unter „Belege“ nachsehen; nur wenn er dort fehlt, den Verkauf erneut abschließen.' },
48
65
  'abschluss.nullbeleg_fehlgeschlagen': { text: 'Der Nullbeleg konnte nicht erstellt werden.' },
49
66
  'abschluss.signatur_ausgefallen': { text: 'Die Signatureinheit hat nicht geantwortet. Der Beleg ist gültig und trägt den Vermerk „Sicherheitseinrichtung ausgefallen“.' },
67
+ // Erledigen darf nur bestaetigen, was am Server auch wirklich steht – sonst
68
+ // gilt ein Betrag als abgehakt, zu dem es nie einen Beleg gab.
69
+ 'abschluss.erledigen_frage': { text: 'Nur erledigen, wenn der Beleg in der Belegliste steht – sonst bleiben {betrag} ohne Beleg. Bitte zuerst unter „Belege“ nachsehen.', platzhalter: ['betrag'] },
50
70
  // --- Kartenzahlung -------------------------------------------------------
51
71
  'kartenzahlung.nicht_moeglich': { text: 'Kartenzahlung nicht möglich.' },
52
72
  'kartenzahlung.nicht_zustande': { text: 'Die Kartenzahlung ist nicht zustande gekommen.' },
53
73
  'kartenzahlung.nicht_gestartet': { text: 'Kartenzahlung nicht gestartet: {grund}', platzhalter: ['grund'] },
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.' },
74
+ '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
75
  // Die Kennung ist der einzige Anker, um die Zahlung am Terminal-Beleg wiederzufinden — liegt sie vor, gilt dieser Satz statt kartenzahlung.unklar.
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'] },
76
+ '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
77
  'kartenzahlung.wartet_auf_terminal': { text: 'Bitte am Terminal fortfahren …' },
78
+ // Das Kartenfenster des Terminals ist abgelaufen: es bricht selbst ab, die
79
+ // Kasse muss nichts tun.
80
+ 'kartenzahlung.terminal_bricht_ab': { text: 'Das Terminal bricht gleich von selbst ab …' },
58
81
  // Ein geglücktes Kartenergebnis ohne Beleg ist der teuerste Zustand am Tresen:
59
82
  // wer hier erneut kassiert, belastet die Karte ein zweites Mal. Beide Sätze
60
83
  // nennen deshalb Betrag UND Kennung — nur damit findet der Kassier die Zahlung
61
84
  // 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'] },
85
+ '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
86
  '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'] },
64
- 'kartenzahlung.connect_nicht_verbunden': { text: 'Kartenzahlung nicht möglich: Kasseneck Connect ist nicht verbunden — Einstellungen → Kasseneck Connect.', nur: ['web'] },
65
- 'terminal.keines_gefunden': { text: 'Kein Hobex-Terminal gefunden — ist es eingeschaltet und im selben Netz wie dieser Rechner?', nur: ['web'] },
66
- 'terminal.nicht_bereit': { text: 'Terminal antwortet, ist aber nicht betriebsbereit: {antwort} — TID prüfen.', platzhalter: ['antwort'], nur: ['web'] },
87
+ 'kartenzahlung.connect_nicht_verbunden': { text: 'Kartenzahlung nicht möglich: Kasseneck Connect ist nicht verbunden – Einstellungen → Kasseneck Connect.', nur: ['web'] },
88
+ // Solange die Karte belastet ist, darf am Korb nichts mehr veraendert werden –
89
+ // sonst passt der Beleg nicht mehr zum Betrag, der schon abgebucht ist.
90
+ 'kartenzahlung.korb_gesperrt_karte_belastet': { text: 'Die Karte ist bereits belastet – Warenkorb, Rabatt und Trinkgeld bleiben gesperrt, bis der Beleg entsteht oder die Karte zurückerstattet ist.' },
91
+ // Entkoppeln trennt das Geraet vom Konto, nicht die gebuchte Kartenzahlung
92
+ // vom Terminal – die muss weiterhin von Hand storniert werden.
93
+ 'kartenzahlung.entkoppeln_karte_belastet': { text: 'Auf diesem Gerät liegt noch eine gebuchte Kartenzahlung ohne Beleg – sie muss von Hand am Terminal zurückerstattet werden (Betrag siehe unten).' },
94
+ 'terminal.keines_gefunden': { text: 'Kein Hobex-Terminal gefunden – ist es eingeschaltet und im selben Netz wie dieser Rechner?', nur: ['web'] },
95
+ 'terminal.nicht_bereit': { text: 'Terminal antwortet, ist aber nicht betriebsbereit: {antwort} – TID prüfen.', platzhalter: ['antwort'], nur: ['web'] },
67
96
  'gptom.app_fehlt': { text: 'Die GP-Tom-App ist auf diesem Gerät nicht da.', nur: ['app'] },
68
97
  'gptom.suche_fehlgeschlagen': { text: 'GP Tom: Suche nach der App fehlgeschlagen: {grund}', platzhalter: ['grund'], nur: ['app'] },
69
98
  'gptom.zahlung_fehlgeschlagen': { text: 'GP Tom: Zahlung fehlgeschlagen: {grund}', platzhalter: ['grund'], nur: ['app'] },
@@ -74,13 +103,13 @@ const MELDUNGEN_ROH = {
74
103
  // liegt einer vor, gilt die Fassung mit Code.
75
104
  'gptom.abgelehnt': { text: 'Das Terminal hat die Zahlung abgelehnt.', nur: ['app'] },
76
105
  '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'] },
106
+ 'gptom.nicht_geoeffnet': { text: 'GP Tom ließ sich nicht öffnen – bitte die GP-Tom-App prüfen und erneut versuchen.', nur: ['app'] },
78
107
  // Frist abgelaufen ist kein Abbruch: die Karte kann belastet sein, nur die
79
108
  // 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'] },
109
+ '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'] },
110
+ '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
111
  // --- Terminal-Protokoll --------------------------------------------------
83
- 'protokoll.leer': { text: 'Noch keine Einträge — das Protokoll füllt sich mit der ersten Kartenzahlung.' },
112
+ 'protokoll.leer': { text: 'Noch keine Einträge – das Protokoll füllt sich mit der ersten Kartenzahlung.' },
84
113
  'protokoll.kopiert': { text: 'Das Protokoll liegt in der Zwischenablage.' },
85
114
  // --- Belege und Storno ---------------------------------------------------
86
115
  'belege.laden_fehlgeschlagen': { text: 'Die Belege konnten nicht geladen werden.' },
@@ -90,6 +119,62 @@ const MELDUNGEN_ROH = {
90
119
  'storno.fehlgeschlagen': { text: 'Das Storno ist fehlgeschlagen.' },
91
120
  'storno.grund_fehlt': { text: 'Bitte einen Grund wählen.' },
92
121
  'storno.position_fehlt': { text: 'Bitte mindestens eine Position wählen.' },
122
+ // Storno eines Belegs mit mehreren Zahlungen: je Zahlung wird zurückgegeben,
123
+ // und der Server prueft jede Rueckgabe gegen den Rest ihrer Zahlung. Welcher
124
+ // Code welchen Satz bekommt, steht in STORNO_ZAHLUNG_FEHLER.
125
+ 'storno.zahlungen_fehlen': { text: 'Dieser Beleg wurde in mehreren Zahlungen bezahlt – bitte angeben, wie zurückgegeben wird.' },
126
+ 'storno.rueckgabe_zu_hoch': { text: 'Eine Rückgabe ist höher als der Rest ihrer Zahlung – bitte die Beträge prüfen.' },
127
+ 'storno.rueckgabe_ohne_bezug': { text: 'Eine Rückgabe nennt keine Zahlung des Belegs – bitte das Storno neu beginnen.' },
128
+ 'storno.rueckgabe_bezug_unbekannt': { text: 'Eine Rückgabe nennt eine Zahlung, die es am Beleg nicht gibt – bitte das Storno neu beginnen.' },
129
+ // Die Antwort kam, aber der Ausgang ist offen: der Storno-Beleg kann schon
130
+ // signiert sein. Wer jetzt noch einmal storniert, storniert womoeglich doppelt.
131
+ 'storno.ergebnis_unklar': { text: 'Unklar, ob das Storno entstanden ist – es kann bereits signiert sein. Bitte nicht erneut stornieren, sondern die Belegliste in ein paar Minuten neu laden.' },
132
+ 'storno.summe_passt_nicht': { text: 'Die Rückgaben ergeben nicht den Betrag des Stornos – bitte die Beträge prüfen.' },
133
+ // Storno eines Belegs mit mehreren Zahlungen: Karten gehen VON HAND am
134
+ // Terminal zurueck, und zwar erst NACH dem gebuchten Storno -- vorher
135
+ // fliesst kein Geld. Darunter steht die Liste der Karten zum Abhaken; der
136
+ // Satz passt fuer eine oder mehrere Karten, mit oder ohne Anbindung.
137
+ 'storno.karten_gutschreiben': { text: 'Das Storno ist gebucht – bitte jede Karte unten am Terminal gutschreiben und abhaken.' },
138
+ // Wie storno.ergebnis_unklar, nur enthielt die Rueckgabe Karten: bevor
139
+ // klar ist, ob das Storno steht, darf keine Gutschrift laufen -- sonst geht
140
+ // Geld zurueck ohne Storno-Beleg.
141
+ 'storno.ergebnis_unklar_karten': { text: 'Unklar, ob das Storno entstanden ist – es kann bereits signiert sein. Bitte nicht erneut stornieren und noch keine Karte gutschreiben, sondern die Belegliste in ein paar Minuten neu laden. Steht das Storno dort, die Karten laut Storno-Beleg am Terminal gutschreiben.' },
142
+ // Die Liste der Karten nach dem gebuchten Storno wird geschlossen, obwohl
143
+ // nicht jede Karte abgehakt ist: einmal nachfragen -- eine vergessene
144
+ // Gutschrift faellt sonst erst dem Gast auf.
145
+ 'storno.karten_nicht_abgehakt': { text: 'Noch ist nicht jede Karte abgehakt – bitte jede am Terminal gutschreiben. Ist das schon geschehen, zum Schließen noch einmal drücken.' },
146
+ // --- Getrennt zahlen -----------------------------------------------------
147
+ // Ein Tisch zahlt in Teilen, ein Beleg fuer alles. Das Teure ist eine schon
148
+ // belastete Karte: jeder Satz, der sie betrifft, nennt den Betrag, und keiner
149
+ // raet dazu, noch einmal zu kassieren.
150
+ 'getrennt.einstellung_hinweis': { text: 'Ein Tisch zahlt in Teilen: jede Zahlung bar oder mit Karte, mit eigenem Trinkgeld – am Ende ein Beleg für alles.' },
151
+ 'getrennt.betrag_ueber_offen': { text: 'Der Betrag ist höher als offen – höchstens {betrag}.', platzhalter: ['betrag'] },
152
+ 'getrennt.trinkgeld_ueber_betrag': { text: 'Das Trinkgeld ist höher als der Betrag dieser Zahlung.' },
153
+ 'getrennt.gegeben_zu_wenig': { text: 'Gegeben ist weniger als der Betrag dieser Zahlung.' },
154
+ 'getrennt.noch_offen': { text: 'Es sind noch {betrag} offen – abschließen geht erst, wenn alles kassiert ist.', platzhalter: ['betrag'] },
155
+ 'getrennt.summe_passt_nicht': { text: 'Die Zahlungen ergeben nicht den Betrag des Belegs – bitte die Liste prüfen.' },
156
+ 'getrennt.korb_gesperrt': { text: 'Der Warenkorb ist gesperrt, solange Zahlungen kassiert sind – erst abschließen oder die Zahlungen entfernen.' },
157
+ 'getrennt.wechsel_gesperrt': { text: 'Zurück zu Bar oder Karte geht erst, wenn keine Zahlung mehr kassiert ist.' },
158
+ 'getrennt.bar_zurueckgeben': { text: 'Bitte {betrag} Bargeld an den Gast zurückgeben.', platzhalter: ['betrag'] },
159
+ 'getrennt.karte_zurueckbuchen_laeuft': { text: 'Die Kartenzahlung über {betrag} wird am Terminal zurückgebucht …', platzhalter: ['betrag'] },
160
+ 'getrennt.karte_zurueckgebucht': { text: 'Die Kartenzahlung über {betrag} ist am Terminal zurückgebucht.', platzhalter: ['betrag'] },
161
+ 'getrennt.karte_zurueckbuchen_fehlgeschlagen': { text: 'Die Kartenzahlung über {betrag} (Kennung {kennung}) ließ sich nicht zurückbuchen – sie bleibt in der Liste. Bitte am Terminal-Beleg nachsehen und erneut versuchen.', platzhalter: ['betrag', 'kennung'] },
162
+ 'getrennt.karte_zurueckbuchen_unklar': { text: 'Unklar, ob die Rückbuchung über {betrag} (Kennung {kennung}) durchgegangen ist – die Zahlung bleibt in der Liste. Bitte am Terminal-Beleg nachsehen, BEVOR erneut zurückgebucht wird.', platzhalter: ['betrag', 'kennung'] },
163
+ // Das Terminal meldet eine Gutschrift, die hier noch als offene Ruecknahme
164
+ // steht – ein zweites Zurueckbuchen waere die doppelte Rueckgabe.
165
+ 'getrennt.karte_bereits_zurueckgebucht': { text: 'Das Terminal meldet, dass die Kartenzahlung über {betrag} bereits gutgeschrieben wurde (Kennung {kennung}) – bitte am Terminal-Beleg prüfen und nicht erneut zurückbuchen.', platzhalter: ['betrag', 'kennung'] },
166
+ 'getrennt.extern_zurueckbuchen': { text: 'Diese Karte ist nicht an die Kasse angebunden. Bitte {betrag} jetzt am Terminal zurückbuchen und danach bestätigen.', platzhalter: ['betrag'] },
167
+ 'getrennt.sitzung_offen': { text: 'Eine getrennte Zahlung ist nicht abgeschlossen, {betrag} sind schon kassiert. Bitte weiter kassieren oder alles zurückbuchen.', platzhalter: ['betrag'] },
168
+ 'getrennt.sitzung_unlesbar': { text: 'Eine gespeicherte getrennte Zahlung auf diesem Gerät ließ sich nicht lesen – bitte prüfen, ob schon Karten belastet wurden (Kasseneck-Panel oder Terminal), und offene Beträge von Hand ausgleichen.' },
169
+ 'getrennt.ablage_fehlgeschlagen': { text: 'Die getrennte Zahlung ließ sich auf diesem Gerät nicht speichern – bitte die Kasse bis zum Abschluss dieses Belegs nicht neu laden, sonst stehen belastete Karten womöglich nicht mehr in der Liste.' },
170
+ 'getrennt.zu_viele_zahlungen': { text: 'Ein Beleg lässt höchstens 20 Zahlungen zu.' },
171
+ 'getrennt.entkoppeln_offene_karten': { text: 'Auf diesem Gerät ist noch eine getrennte Zahlung mit belasteten Karten offen – sie müssen von Hand am Terminal zurückgebucht werden (Beträge siehe unten).' },
172
+ 'getrennt.positionen_gesperrt': { text: 'Nach Positionen geht nicht mehr – eine Zahlung ist schon als Betrag kassiert.' },
173
+ 'getrennt.positionen_waehlen': { text: 'Bitte zuerst antippen, was dieser Gast zahlt.' },
174
+ // Barzahlung mit Rueckgeld-Rechner: ohne „Gegeben" wird die Zahlung nicht
175
+ // hinzugefuegt – derselbe Grund wie beim Abschluss einer Barzahlung, auf
176
+ // DIESE Zahlung bezogen.
177
+ 'getrennt.gegeben_fehlt': { text: 'Erst eintippen, was der Gast für diese Zahlung gibt – der Rückgeld-Rechner ist an.' },
93
178
  // --- Beleg weitergeben: Link, Teilen, E-Mail -----------------------------
94
179
  // Kopieren, Teilen und Senden fuehren zu demselben Ziel: der oeffentlichen
95
180
  // Belegseite (beleg.kasseneck.at/<fullReceiptId>). Kein Satz davon ist
@@ -102,29 +187,29 @@ const MELDUNGEN_ROH = {
102
187
  // Belege aus dem Altbestand tragen keine `fullReceiptId`; ohne sie gibt es
103
188
  // keine Belegseite. Der Satz nennt den Grund, sonst sucht der Kassier den
104
189
  // 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.' },
190
+ 'beleg.nicht_teilbar': { text: 'Für diesen Beleg gibt es keinen Link – er stammt aus einer älteren Kasse.' },
106
191
  // Ein Testbeleg hat eine Belegseite, ist aber steuerlich nichts wert. Wer
107
192
  // den Link weitergibt, muss das vorher lesen, nicht hinterher.
108
- 'beleg.test_hinweis_teilen': { text: 'Test-Umgebung — der Beleg ist steuerlich nicht gültig.' },
193
+ 'beleg.test_hinweis_teilen': { text: 'Test-Umgebung – der Beleg ist steuerlich nicht gültig.' },
109
194
  'beleg.mail_gesendet': { text: 'Der Beleg wurde an {an} gesendet.', platzhalter: ['an'] },
110
195
  '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.' },
196
+ 'beleg.mail_zu_oft': { text: 'Dieser Beleg wurde schon oft gesendet – bitte später noch einmal.' },
112
197
  'beleg.mail_fehlgeschlagen': { text: 'Der Beleg konnte nicht gesendet werden. Bitte noch einmal versuchen.' },
113
198
  // Bewusst nicht derselbe Satz wie `beleg.nicht_gefunden`: dort scheitert das
114
199
  // Oeffnen, hier das Senden. Der Kassier steht vor einem Adressfeld und muss
115
200
  // lesen, dass nichts hinausgegangen ist.
116
- 'beleg.mail_nicht_gefunden': { text: 'Dieser Beleg wurde nicht gefunden — er konnte nicht gesendet werden.' },
201
+ 'beleg.mail_nicht_gefunden': { text: 'Dieser Beleg wurde nicht gefunden – er konnte nicht gesendet werden.' },
117
202
  // --- Druck ---------------------------------------------------------------
118
203
  'druck.fehlgeschlagen': { text: 'Der Ausdruck ist fehlgeschlagen.' },
119
204
  'druck.nicht_moeglich': { text: 'Druck nicht möglich: {grund}', platzhalter: ['grund'] },
120
205
  'druck.testdruck_fehlgeschlagen': { text: 'Der Testdruck ist fehlgeschlagen.' },
121
206
  'druck.testdruck_nicht_moeglich': { text: 'Der Testdruck ist fehlgeschlagen: {grund}', platzhalter: ['grund'] },
122
- 'druck.kein_drucker': { text: 'Kein Bondrucker eingerichtet — in den Einstellungen unter Drucker & Lade.' },
207
+ 'druck.kein_drucker': { text: 'Kein Bondrucker eingerichtet – in den Einstellungen unter Drucker & Lade.' },
123
208
  'druck.drucker_nicht_erreichbar': { text: 'Drucker nicht erreichbar.' },
124
209
  'druck.job_abgelaufen': { text: 'Drucker hat den Beleg nicht abgeholt (abgelaufen).', nur: ['web'] },
125
- 'druck.kein_drucker_gefunden': { text: 'Kein Drucker gefunden — ist er eingeschaltet und im selben Netz wie dieser Rechner?', nur: ['web'] },
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'] },
127
- 'druck.kein_weg_drucker': { text: 'Kein {weg}-Drucker verbunden — „{weg}-Drucker verbinden“ und den Drucker im Dialog wählen.', platzhalter: ['weg'], nur: ['web'] },
210
+ 'druck.kein_drucker_gefunden': { text: 'Kein Drucker gefunden – ist er eingeschaltet und im selben Netz wie dieser Rechner?', nur: ['web'] },
211
+ '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'] },
212
+ 'druck.kein_weg_drucker': { text: 'Kein {weg}-Drucker verbunden – „{weg}-Drucker verbinden“ und den Drucker im Dialog wählen.', platzhalter: ['weg'], nur: ['web'] },
128
213
  // Der Drucker-Wizard: suchen, verbinden, Testdruck, QR-Probe, erst dann
129
214
  // speichern. Derselbe Ablauf in beiden Kassen — deshalb hat kein Satz ein
130
215
  // `nur`, obwohl der Weg zum Drucker verschieden ist (Bluetooth in der App,
@@ -135,7 +220,7 @@ const MELDUNGEN_ROH = {
135
220
  // Kein Modus druckt einen lesbaren QR-Code: gespeichert wird trotzdem (mit
136
221
  // Raster als Vorgabe), aber der Chef muss wissen, dass der QR-Code dann vom
137
222
  // 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.' },
223
+ 'druck.wizard_qr_keiner_hinweis': { text: 'Kein QR-Code kam sauber – der Beleg zeigt den QR-Code dann am Bildschirm.' },
139
224
  'druck.wizard_nichts_gekommen': { text: 'Nichts gekommen? Drucker an, Papier drin, richtiges Gerät gewählt?' },
140
225
  'druck.wizard_gespeichert': { text: '{name} ist eingerichtet.', platzhalter: ['name'] },
141
226
  // Abbrechen an jeder Stelle: nichts gespeichert. Der Satz sagt genau das,
@@ -145,24 +230,25 @@ const MELDUNGEN_ROH = {
145
230
  'bluetooth.freigabe_fehlt': { text: 'Bitte die Freigabe in den Geräte-Einstellungen erteilen.', nur: ['app'] },
146
231
  'bluetooth.suche_fehlgeschlagen': { text: 'Die Suche ist fehlgeschlagen: {grund}', platzhalter: ['grund'], nur: ['app'] },
147
232
  // --- Kasseneck Connect (nur Browser) -------------------------------------
148
- 'connect.antwortet_nicht': { text: 'Kasseneck Connect antwortet nicht — läuft das Programm auf diesem Rechner?', nur: ['web'] },
149
- 'connect.code_abgelaufen': { text: 'Der Kopplungs-Code ist abgelaufen — im Agent einen neuen erzeugen („kasseneck-connect pair“).', nur: ['web'] },
150
- 'connect.zu_viele_versuche': { text: 'Zu viele Fehlversuche — eine Minute warten und noch einmal versuchen.', nur: ['web'] },
151
- 'connect.drucker_antwortet_nicht': { text: 'Der Drucker antwortet nicht — Strom, Netzwerk und IP prüfen.', nur: ['web'] },
152
- 'connect.nicht_gekoppelt': { text: 'Diese Kasse ist mit Kasseneck Connect nicht gekoppelt — in den Einstellungen „Koppeln“ drücken.', nur: ['web'] },
153
- 'connect.drucker_unbekannt': { text: 'Diesen Drucker kennt Kasseneck Connect nicht (mehr) — bitte neu suchen.', nur: ['web'] },
233
+ 'connect.antwortet_nicht': { text: 'Kasseneck Connect antwortet nicht – läuft das Programm auf diesem Rechner?', nur: ['web'] },
234
+ 'connect.code_abgelaufen': { text: 'Der Kopplungs-Code ist abgelaufen – im Agent einen neuen erzeugen („kasseneck-connect pair“).', nur: ['web'] },
235
+ 'connect.zu_viele_versuche': { text: 'Zu viele Fehlversuche – eine Minute warten und noch einmal versuchen.', nur: ['web'] },
236
+ 'connect.drucker_antwortet_nicht': { text: 'Der Drucker antwortet nicht – Strom, Netzwerk und IP prüfen.', nur: ['web'] },
237
+ 'connect.nicht_gekoppelt': { text: 'Diese Kasse ist mit Kasseneck Connect nicht gekoppelt – in den Einstellungen „Koppeln“ drücken.', nur: ['web'] },
238
+ 'connect.drucker_unbekannt': { text: 'Diesen Drucker kennt Kasseneck Connect nicht (mehr) – bitte neu suchen.', nur: ['web'] },
154
239
  'connect.ursprung_nicht_freigegeben': { text: 'Kasseneck Connect nimmt von dieser Adresse nichts an (Ursprung nicht freigegeben).', nur: ['web'] },
155
- 'connect.nicht_installiert': { text: 'Kasseneck Connect nicht gefunden — bitte installieren.', nur: ['web'] },
240
+ 'connect.nicht_installiert': { text: 'Kasseneck Connect nicht gefunden – bitte installieren.', nur: ['web'] },
241
+ 'connect.entkoppeln_frage': { text: 'Diesen Browser wirklich von Connect trennen? Der Bondruck geht dann nicht mehr.', nur: ['web'] },
156
242
  // --- Einstellungen -------------------------------------------------------
157
243
  'einstellungen.laden_fehlgeschlagen': { text: 'Die Einstellungen konnten nicht geladen werden.' },
158
244
  'einstellungen.speichern_fehlgeschlagen': { text: 'Die Einstellung konnte nicht gespeichert werden.' },
159
- 'einstellungen.noch_nicht_geladen': { text: 'Noch nicht geladen — bitte kurz warten oder neu anmelden.' },
245
+ 'einstellungen.noch_nicht_geladen': { text: 'Noch nicht geladen – bitte kurz warten oder neu anmelden.' },
160
246
  'einstellungen.ip_ungueltig': { text: 'Keine gültige IP-Adresse (z. B. 192.168.1.50).' },
161
247
  'entkopplung.fehlgeschlagen': { text: 'Entkoppeln fehlgeschlagen.' },
162
248
  'logo.hochladen_fehlgeschlagen': { text: 'Hochladen fehlgeschlagen.' },
163
249
  'logo.entfernen_fehlgeschlagen': { text: 'Entfernen fehlgeschlagen.' },
164
250
  // --- Nur App -------------------------------------------------------------
165
- 'app.nicht_im_browser': { text: 'Die Kassen-App läuft nicht im Browser — dafür gibt es kasse.kasseneck.at.', nur: ['app'] },
251
+ 'app.nicht_im_browser': { text: 'Die Kassen-App läuft nicht im Browser – dafür gibt es kasse.kasseneck.at.', nur: ['app'] },
166
252
  'app.im_browser_oeffnen': { text: 'Bitte im Browser öffnen: {ziel}', platzhalter: ['ziel'], nur: ['app'] },
167
253
  };
168
254
  // Auf den gemeinsamen Typ gebracht: `Object.entries(MELDUNGEN)` liefert sonst
@@ -221,6 +307,148 @@ export function belegMailFehler(code) {
221
307
  const fehler = BELEG_MAIL_FEHLER;
222
308
  return (code !== undefined && code !== null && fehler[code]) || 'beleg.mail_fehlgeschlagen';
223
309
  }
310
+ /**
311
+ * Storno eines Belegs mit mehreren Zahlungen, dazu der offene Ausgang
312
+ * (`STORNO_OUTCOME_UNKNOWN`, gilt fuer jedes Storno): welcher `code` des
313
+ * Backends welchen Satz bekommt. Dieselbe Idee wie BELEG_MAIL_FEHLER – beide Kassen
314
+ * entscheiden am Code, nie am Satz des Backends. Ein Code, der hier fehlt,
315
+ * geht den allgemeinen Weg der Storno-Fehler (`storno.fehlgeschlagen`).
316
+ */
317
+ export const STORNO_ZAHLUNG_FEHLER = {
318
+ STORNO_PAYMENTS_REQUIRED: 'storno.zahlungen_fehlen',
319
+ STORNO_REFUND_EXCEEDS_PAYMENT: 'storno.rueckgabe_zu_hoch',
320
+ STORNO_REFUND_REFERENCE_REQUIRED: 'storno.rueckgabe_ohne_bezug',
321
+ STORNO_REFUND_REFERENCE_UNKNOWN: 'storno.rueckgabe_bezug_unbekannt',
322
+ PAYMENTS_SUM_MISMATCH: 'storno.summe_passt_nicht',
323
+ STORNO_OUTCOME_UNKNOWN: 'storno.ergebnis_unklar',
324
+ };
325
+ /**
326
+ * Der Satz zu einem `code` des Backends beim Storno mit mehreren Zahlungen.
327
+ * Einen Code, den dieses Paket noch nicht kennt, faengt der allgemeine Satz
328
+ * `storno.fehlgeschlagen` auf – wie bei `belegMailFehler`.
329
+ */
330
+ export function stornoZahlungFehler(code) {
331
+ const fehler = STORNO_ZAHLUNG_FEHLER;
332
+ return (code !== undefined && code !== null && fehler[code]) || 'storno.fehlgeschlagen';
333
+ }
334
+ /**
335
+ * Beschriftungen: Knoepfe, Ueberschriften, Zeilennamen – was kein Satz ist.
336
+ *
337
+ * Getrennt von MELDUNGEN, weil dort jeder Eintrag ein Satz ist (gross am
338
+ * Anfang, Satzzeichen am Schluss) und die Waechter beider Kassen daran
339
+ * Saetze erkennen. „Rest" oder „÷ {n}" sind keine Saetze, muessen aber in
340
+ * beiden Kassen gleich heissen. Dieselben Regeln sonst: Schluessel
341
+ * `bereich.name`, nie umgedeutet, Platzhalter exakt die im Text, `nur` nennt
342
+ * die Seite.
343
+ *
344
+ * Die Woerter der Zahlarten folgen dem Bon („Kartenzahlung", „Barzahlung",
345
+ * „Zahlung {n}", „davon Trinkgeld").
346
+ */
347
+ const BESCHRIFTUNGEN_ROH = {
348
+ // --- Allgemein -------------------------------------------------------------
349
+ 'allgemein.abbrechen': { text: 'Abbrechen' },
350
+ // Das X an einer Meldung nennt, WELCHE es ausblendet – bei mehreren
351
+ // Meldungen in der Ecke sonst fuer Vorlese-Programme lauter gleiche Knoepfe.
352
+ // `{meldung}` ist der Anfang des Satzes (gekuerzt), nicht der ganze.
353
+ 'meldung.ausblenden': { text: 'Meldung ausblenden: {meldung}', platzhalter: ['meldung'] },
354
+ 'meldung.warnung_ausblenden': { text: 'Verstanden – Warnung ausblenden: {meldung}', platzhalter: ['meldung'] },
355
+ // --- Kopplung und Abmelden -----------------------------------------------
356
+ 'kopplung.neu_koppeln': { text: 'Neu koppeln' },
357
+ 'abmelden.frage': { text: 'Wirklich abmelden?' },
358
+ 'abmelden.weiter_arbeiten': { text: 'Weiter arbeiten' },
359
+ 'geraet.entkoppeln': { text: 'Gerät entkoppeln' },
360
+ 'connect.entkoppeln_bestaetigen': { text: 'Entkoppeln bestätigen', nur: ['web'] },
361
+ // --- Kassieren -------------------------------------------------------------
362
+ // Dieselben Woerter im gewohnten Kassieren und je Zahlung bei „Getrennt“.
363
+ 'kassieren.trinkgeld': { text: 'Trinkgeld' },
364
+ 'kassieren.kein': { text: 'kein' },
365
+ 'kassieren.eigener_betrag': { text: 'Eigener Betrag' },
366
+ 'kassieren.passend': { text: 'passend' },
367
+ 'kassieren.gegeben_loeschen': { text: 'Gegeben löschen' },
368
+ 'kassieren.es_fehlen_noch': { text: 'Es fehlen noch' },
369
+ 'kassieren.rueckgeld': { text: 'Rückgeld' },
370
+ // Die Warte-Karte, solange der Betrag am Terminal steht; `{zeit}` ist der
371
+ // Rest des Kartenfensters als m:ss.
372
+ 'kartenzahlung.betrag_am_terminal': { text: 'Betrag steht am Terminal' },
373
+ 'kartenzahlung.karte_vorhalten': { text: 'Karte vorhalten oder stecken · noch {zeit}', platzhalter: ['zeit'] },
374
+ // --- Abschluss -------------------------------------------------------------
375
+ 'abschluss.beleg_vorhanden': { text: 'Beleg ist vorhanden – erledigen' },
376
+ 'abschluss.erledigen': { text: 'Erledigen' },
377
+ // --- Getrennt zahlen -----------------------------------------------------
378
+ 'getrennt.knopf': { text: 'Getrennt' },
379
+ 'getrennt.einstellung': { text: 'Getrennt zahlen' },
380
+ 'getrennt.zu_zahlen': { text: 'Zu zahlen' },
381
+ 'getrennt.offen': { text: 'Offen' },
382
+ 'getrennt.zahlung': { text: 'Zahlung {n}', platzhalter: ['n'] },
383
+ 'getrennt.betrag': { text: 'Betrag' },
384
+ 'getrennt.rest': { text: 'Rest' },
385
+ 'getrennt.teilen': { text: '÷ {n}', platzhalter: ['n'] },
386
+ 'getrennt.trinkgeld_bezug': { text: '% von diesem Betrag' },
387
+ 'getrennt.davon_trinkgeld': { text: 'davon Trinkgeld {betrag}', platzhalter: ['betrag'] },
388
+ 'getrennt.entfernen': { text: 'Entfernen' },
389
+ 'getrennt.alles_abbrechen': { text: 'Alles abbrechen' },
390
+ 'getrennt.weiter_kassieren': { text: 'Weiter kassieren' },
391
+ 'getrennt.alles_zurueckbuchen': { text: 'Alles zurückbuchen' },
392
+ 'getrennt.am_terminal_zurueckgebucht': { text: 'Am Terminal zurückgebucht' },
393
+ 'getrennt.karte_zurueckbuchen': { text: 'Karte zurückbuchen' },
394
+ 'getrennt.trotzdem_neu_koppeln': { text: 'Trotzdem neu koppeln' },
395
+ 'getrennt.zahlung_behalten': { text: 'Zahlung behalten' },
396
+ 'getrennt.klaeren': { text: 'Klären' },
397
+ 'getrennt.erneut_zurueckbuchen': { text: 'Erneut zurückbuchen' },
398
+ 'getrennt.wurde_belastet': { text: 'Wurde belastet – übernehmen' },
399
+ 'getrennt.nicht_belastet': { text: 'Nicht belastet – verwerfen' },
400
+ // Aufteilung: eigener Schritt nach „Weiter“, Tabs „Nach Positionen“ / „Betrag“.
401
+ 'getrennt.weiter': { text: 'Weiter · {betrag} getrennt', platzhalter: ['betrag'] },
402
+ 'getrennt.aufteilung': { text: 'Aufteilung' },
403
+ 'getrennt.zurueck_zahlart': { text: 'Zurück zur Zahlart' },
404
+ 'getrennt.tab_positionen': { text: 'Nach Positionen' },
405
+ 'getrennt.tab_betrag': { text: 'Betrag' },
406
+ 'getrennt.stueck_weniger': { text: '{name}: ein Stück weniger', platzhalter: ['name'] },
407
+ 'getrennt.stueck_mehr': { text: '{name}: ein Stück mehr', platzhalter: ['name'] },
408
+ 'getrennt.gegeben': { text: 'Gegeben (bar)' },
409
+ 'getrennt.gegeben_rueckgeld': { text: 'Gegeben {gegeben} · Rückgeld {rueckgeld}', platzhalter: ['gegeben', 'rueckgeld'] },
410
+ // Je Zahlung oben die Zahlart (Umschalter, kein Ausloeser), unten EIN Knopf,
411
+ // der diese Zahlung mit der gewaehlten Zahlart kassiert.
412
+ 'getrennt.zahlart': { text: 'Zahlart' },
413
+ 'getrennt.art_bar': { text: 'Bar' },
414
+ 'getrennt.art_karte': { text: 'Karte' },
415
+ 'getrennt.zahlung_hinzufuegen': { text: 'Zahlung hinzufügen · {betrag}', platzhalter: ['betrag'] },
416
+ // Nach Positionen: die offenen Stueck als Kacheln in der grossen Flaeche;
417
+ // Antippen nimmt ein Stueck in diese Zahlung, „−“ an der Kachel eines heraus.
418
+ 'getrennt.offene_positionen': { text: 'Offene Positionen' },
419
+ 'getrennt.stueck_offen': { text: '{n} offen', platzhalter: ['n'] },
420
+ 'getrennt.stueck_gewaehlt': { text: '{n} von {offen}', platzhalter: ['n', 'offen'] },
421
+ 'getrennt.nichts_gewaehlt': { text: 'Noch nichts angetippt' },
422
+ 'getrennt.alles_bezahlt': { text: 'Alles bezahlt' },
423
+ // --- Zahlarten in Listen (Kassieren, Storno, Belegliste) -----------------
424
+ 'zahlart.kartenzahlung': { text: 'Kartenzahlung' },
425
+ 'zahlart.barzahlung': { text: 'Barzahlung' },
426
+ // Beleg mit mehreren Zahlungen (`paymentMethod: 'mixed'` oder mehr als eine
427
+ // Zahlung): weder Bar noch Karte, auch nicht im Filter.
428
+ 'zahlart.mehrere': { text: 'Mehrere' },
429
+ // --- Storno ----------------------------------------------------------------
430
+ 'storno.titel': { text: 'Storno zu {beleg}', platzhalter: ['beleg'] },
431
+ // --- Storno eines Belegs mit mehreren Zahlungen --------------------------
432
+ 'storno.wie_zurueckgeben': { text: 'Wie zurückgeben?' },
433
+ 'storno.wie_bezahlt': { text: 'wie bezahlt' },
434
+ 'storno.bar': { text: 'bar' },
435
+ 'storno.alles_bar': { text: 'Alles bar' },
436
+ 'storno.rest_der_zahlung': { text: 'Rest {betrag}', platzhalter: ['betrag'] },
437
+ 'storno.differenz': { text: 'Differenz' },
438
+ };
439
+ export const BESCHRIFTUNGEN = BESCHRIFTUNGEN_ROH;
440
+ /** Die Beschriftung zum Schluessel, Platzhalter ersetzt; fehlt ein Wert, wirft es wie `meldung`. */
441
+ export function beschriftung(schluessel, werte = {}) {
442
+ return ersetze(`beschriftung(${schluessel})`, BESCHRIFTUNGEN[schluessel].text, werte);
443
+ }
444
+ function ersetze(wo, text, werte) {
445
+ return text.replace(/\{([a-z]+)\}/g, (_, name) => {
446
+ const wert = werte[name];
447
+ if (wert === undefined)
448
+ throw new Error(`${wo}: Platzhalter {${name}} ohne Wert`);
449
+ return String(wert);
450
+ });
451
+ }
224
452
  /** Der Satz zum Schluessel, Platzhalter ersetzt. Fehlt ein Wert, wirft es — ein `{status}` am Tresen waere schlimmer. */
225
453
  export function meldung(schluessel, werte = {}) {
226
454
  const eintrag = MELDUNGEN[schluessel];
@@ -20,15 +20,28 @@ export type CancellationReason = keyof typeof CANCELLATION_REASONS;
20
20
  export declare function isCancellationReason(value: unknown): value is CancellationReason;
21
21
  /**
22
22
  * Stabile Fehlercodes von `cancelReceipt` — Zwilling von
23
- * `functions/storno-core.js` STORNO_FEHLERCODES. Das Backend legt sie bei
23
+ * `functions/gemeinsam/storno-core.js` STORNO_FEHLERCODES. Das Backend legt sie bei
24
24
  * jedem fachlichen Fehler als `code` neben die Meldung; das Paket reicht sie
25
25
  * als [KasseneckApiError.code] durch. **Entscheide am Code, nie am Text** —
26
26
  * die deutsche Meldung darf sich aendern, der Code nicht.
27
27
  *
28
28
  * Nur Auth-/Parameterfehler (Sitzung abgelaufen, Pflichtfeld fehlt) kommen
29
29
  * ohne Code; dort bleibt `code` undefined.
30
+ *
31
+ * Die vier `STORNO_PAYMENTS_…`/`STORNO_REFUND_…`-Codes gehoeren zur
32
+ * Rueckzahlung je Zahlung (mehrere Zahlungen je Beleg); Formfehler an
33
+ * `payments` selbst melden die Codes aus [PAYMENT_ERROR_CODES].
34
+ * `STORNO_OUTCOME_UNKNOWN` heisst: der Storno-Beleg kann schon signiert sein,
35
+ * die Reservierung bleibt offen – nicht erneut stornieren, die Belegliste
36
+ * nach ein paar Minuten neu laden (unter `/v3`: `cancellation_outcome_unknown`).
37
+ *
38
+ * Die Werte hier sind die von `/v1` und intern. Unter `/v3` heissen die
39
+ * Storno-Codes nach dem /v3-Vokabular anders (`already_cancelled`,
40
+ * `cancellation_payments_required`, functions/gemeinsam/api-vokabular-v3.js);
41
+ * diese Namen kommen mit der Umstellung des Pakets auf `/v3`.
42
+ * [isCancellationErrorCode] prueft darum exakt.
30
43
  */
31
- export declare const CANCELLATION_ERROR_CODES: readonly ["beleg_nicht_gefunden", "belegart_nicht_stornierbar", "trainingsbeleg", "bereits_storniert", "position_ungueltig", "menge_ueber_rest", "grund_unbekannt", "anmerkung_zu_lang", "items_ungueltig", "kasse_nicht_zugewiesen", "keine_berechtigung", "nur_eigene_belege", "kasse_unvollstaendig", "storno_fehlgeschlagen"];
44
+ export declare const CANCELLATION_ERROR_CODES: readonly ["beleg_nicht_gefunden", "belegart_nicht_stornierbar", "trainingsbeleg", "bereits_storniert", "position_ungueltig", "menge_ueber_rest", "grund_unbekannt", "anmerkung_zu_lang", "items_ungueltig", "kasse_nicht_zugewiesen", "keine_berechtigung", "nur_eigene_belege", "kasse_unvollstaendig", "storno_fehlgeschlagen", "STORNO_PAYMENTS_REQUIRED", "STORNO_REFUND_EXCEEDS_PAYMENT", "STORNO_REFUND_REFERENCE_REQUIRED", "STORNO_REFUND_REFERENCE_UNKNOWN", "STORNO_OUTCOME_UNKNOWN"];
32
45
  export type CancellationErrorCode = (typeof CANCELLATION_ERROR_CODES)[number];
33
46
  export declare function isCancellationErrorCode(value: unknown): value is CancellationErrorCode;
34
47
  /** Bezug eines Storno-Belegs auf sein Original. */
@@ -68,6 +81,16 @@ export interface Cancellation {
68
81
  * nichts gewaehrt (Altbestand vor dieser Regel) — der naechste Storno holt nach.
69
82
  */
70
83
  promoAdjustmentCents?: Record<string, number>;
84
+ /**
85
+ * Rueckzahlung je Zahlung, die DIESER Storno-Eintrag auf eine Zahlung des
86
+ * Originals verbucht hat (`refundOf`) -- Zahlungs-ID auf positive Cent,
87
+ * Zwilling von `functions/gemeinsam/storno-core.js` `refundedByPayment`.
88
+ * Ueber alle Eintraege darf je Zahlung nie mehr zurueck, als bezahlt wurde
89
+ * (siehe dort `restJeZahlung`). Ein Eintrag ohne das Feld (vor dieser Regel
90
+ * oder ohne Zahlungsmodell gebucht) zaehlt dabei 0 je Zahlung. Auch am
91
+ * `pending`-Eintrag vorhanden, sobald reserviert wird.
92
+ */
93
+ refundedByPayment?: Record<string, number>;
71
94
  }
72
95
  /** Ab wann eine liegengebliebene Reservierung nicht mehr zaehlt (wie im Backend). */
73
96
  export declare const CANCELLATION_RESERVATION_MS = 120000;
@@ -20,13 +20,26 @@ export function isCancellationReason(value) {
20
20
  }
21
21
  /**
22
22
  * Stabile Fehlercodes von `cancelReceipt` — Zwilling von
23
- * `functions/storno-core.js` STORNO_FEHLERCODES. Das Backend legt sie bei
23
+ * `functions/gemeinsam/storno-core.js` STORNO_FEHLERCODES. Das Backend legt sie bei
24
24
  * jedem fachlichen Fehler als `code` neben die Meldung; das Paket reicht sie
25
25
  * als [KasseneckApiError.code] durch. **Entscheide am Code, nie am Text** —
26
26
  * die deutsche Meldung darf sich aendern, der Code nicht.
27
27
  *
28
28
  * Nur Auth-/Parameterfehler (Sitzung abgelaufen, Pflichtfeld fehlt) kommen
29
29
  * ohne Code; dort bleibt `code` undefined.
30
+ *
31
+ * Die vier `STORNO_PAYMENTS_…`/`STORNO_REFUND_…`-Codes gehoeren zur
32
+ * Rueckzahlung je Zahlung (mehrere Zahlungen je Beleg); Formfehler an
33
+ * `payments` selbst melden die Codes aus [PAYMENT_ERROR_CODES].
34
+ * `STORNO_OUTCOME_UNKNOWN` heisst: der Storno-Beleg kann schon signiert sein,
35
+ * die Reservierung bleibt offen – nicht erneut stornieren, die Belegliste
36
+ * nach ein paar Minuten neu laden (unter `/v3`: `cancellation_outcome_unknown`).
37
+ *
38
+ * Die Werte hier sind die von `/v1` und intern. Unter `/v3` heissen die
39
+ * Storno-Codes nach dem /v3-Vokabular anders (`already_cancelled`,
40
+ * `cancellation_payments_required`, functions/gemeinsam/api-vokabular-v3.js);
41
+ * diese Namen kommen mit der Umstellung des Pakets auf `/v3`.
42
+ * [isCancellationErrorCode] prueft darum exakt.
30
43
  */
31
44
  export const CANCELLATION_ERROR_CODES = [
32
45
  'beleg_nicht_gefunden', // Original fehlt oder gehoert nicht zu dieser Kasse
@@ -43,6 +56,12 @@ export const CANCELLATION_ERROR_CODES = [
43
56
  'nur_eigene_belege', // Recht "eigene", fremder Beleg
44
57
  'kasse_unvollstaendig', // api_key/token fehlen am Konto bzw. an der Kasse
45
58
  'storno_fehlgeschlagen', // der Storno-Beleg selbst wurde abgelehnt (z. B. Signatur)
59
+ // Mehrere Zahlungen je Beleg (Rueckzahlung je Zahlung):
60
+ 'STORNO_PAYMENTS_REQUIRED', // Teilstorno eines Belegs mit mehreren Zahlungen ohne payments
61
+ 'STORNO_REFUND_EXCEEDS_PAYMENT', // Rueckzahlungen auf eine Zahlung uebersteigen deren Rest
62
+ 'STORNO_REFUND_REFERENCE_REQUIRED', // Karten-Rueckzahlung ohne refundOf einer Kartenzahlung
63
+ 'STORNO_REFUND_REFERENCE_UNKNOWN', // refundOf nennt keine Zahlung des Originals
64
+ 'STORNO_OUTCOME_UNKNOWN', // Ausgang offen: Storno-Beleg evtl. schon signiert, nicht wiederholen
46
65
  ];
47
66
  export function isCancellationErrorCode(value) {
48
67
  return typeof value === 'string' && CANCELLATION_ERROR_CODES.includes(value);
@@ -2,6 +2,8 @@ export { type ReceiptItem, type ReceiptItemPayload, type ReceiptItemPayloadRead,
2
2
  export { type Voucher, type VoucherPayload, toVoucherPayload, fromVoucherPayload, voucherIsValid } from './voucher.js';
3
3
  export { type Receipt, type ReceiptPayload, type ReceiptPayloadRead, toReceiptPayload, fromReceiptPayload, receiptSubSumCents, receiptSumCents, } from './receipt.js';
4
4
  export { type CancellationOf, type CancellationItem, type Cancellation, type CancellationReason, type CancellationErrorCode, CANCELLATION_REASONS, CANCELLATION_ERROR_CODES, CANCELLATION_RESERVATION_MS, isCancellationReason, isCancellationErrorCode, remainingQuantities, } from './cancellation.js';
5
+ export { type ReceiptPayment, type ReceiptPaymentPayload, type ReceiptPaymentInput, fromReceiptPaymentPayload, toReceiptPaymentPayload, } from './receipt-payment.js';
6
+ export { type PaymentErrorCode, PAYMENT_ERROR_CODES, isPaymentErrorCode } from './payment-errors.js';
5
7
  export { type ReceiptEmailErrorCode, RECEIPT_EMAIL_ERROR_CODES, isReceiptEmailErrorCode, } from './receipt-email.js';
6
8
  export { type ReceiptCompany, type ReceiptCompanyPayload, fromReceiptCompanyPayload, receiptCompanyTaxInfo, } from './receipt-company.js';
7
9
  export { type Cashregister, type CashregisterOnboarding, type CashregisterPayload, type CashregisterOnboardingPayload, fromCashregisterPayload, } from './cashregister.js';
@@ -2,6 +2,8 @@ export { toReceiptItemPayload, fromReceiptItemPayload, receiptItemTotalCents, re
2
2
  export { toVoucherPayload, fromVoucherPayload, voucherIsValid } from './voucher.js';
3
3
  export { toReceiptPayload, fromReceiptPayload, receiptSubSumCents, receiptSumCents, } from './receipt.js';
4
4
  export { CANCELLATION_REASONS, CANCELLATION_ERROR_CODES, CANCELLATION_RESERVATION_MS, isCancellationReason, isCancellationErrorCode, remainingQuantities, } from './cancellation.js';
5
+ export { fromReceiptPaymentPayload, toReceiptPaymentPayload, } from './receipt-payment.js';
6
+ export { PAYMENT_ERROR_CODES, isPaymentErrorCode } from './payment-errors.js';
5
7
  export { RECEIPT_EMAIL_ERROR_CODES, isReceiptEmailErrorCode, } from './receipt-email.js';
6
8
  export { fromReceiptCompanyPayload, receiptCompanyTaxInfo, } from './receipt-company.js';
7
9
  export { fromCashregisterPayload, } from './cashregister.js';
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Mehrere Zahlungen je Beleg — Fehlercode-Katalog, Zwilling von
3
+ * `functions/gemeinsam/zahlungen-core.js` ZAHLUNGS_FEHLERCODES (gleiche
4
+ * Codes, gleiche Reihenfolge).
5
+ *
6
+ * `createReceipt` und `cancelReceipt` legen sie bei jedem Fehler rund um
7
+ * `payments` (und bei den Aufrufer-Vorbedingungen wie `PAYMENTS_CONFLICT`)
8
+ * als `code` neben die Meldung; das Paket reicht sie als
9
+ * [KasseneckApiError.code] durch. **Entscheide am Code, nie am Text** — die
10
+ * deutsche Meldung darf sich aendern, der Code nicht.
11
+ *
12
+ * Schreibweise: auf `/v1`, `/v2` und intern kommen die Codes gross
13
+ * (`PAYMENTS_SUM_MISMATCH`), unter `/v3` schreibt der Rand des Backends sie
14
+ * klein (`payments_sum_mismatch`, functions/gemeinsam/api-vokabular-v3.js:
15
+ * jeder dieser Codes 1:1 in Kleinschreibung, anders als die Storno-Codes).
16
+ * [isPaymentErrorCode] erkennt beide; wer selbst vergleicht, vergleicht
17
+ * `code.toUpperCase()`.
18
+ */
19
+ export declare const PAYMENT_ERROR_CODES: readonly ["PAYMENTS_INVALID", "PAYMENT_METHOD_INVALID", "PAYMENT_AMOUNT_INVALID", "PAYMENT_TENDERED_INVALID", "PAYMENT_PROVIDER_INVALID", "PAYMENT_PROVIDER_NOT_ALLOWED", "PAYMENTS_SUM_MISMATCH", "PAYMENTS_DUE_NEGATIVE", "PAYMENTS_NOT_ALLOWED", "PAYMENTS_CONFLICT", "PAYMENTS_REQUIRED", "PAYMENT_METHOD_NOT_SUPPORTED", "TIP_PAYMENT_METHOD_INVALID", "TIP_PAYMENT_METHOD_REQUIRED", "TIP_EXCEEDS_PAYMENT", "PAYMENT_REFUND_NOT_ALLOWED", "PAYMENT_TIP_INVALID", "TIP_CONFLICT"];
20
+ export type PaymentErrorCode = (typeof PAYMENT_ERROR_CODES)[number];
21
+ /** Erkennt einen Code aus [PAYMENT_ERROR_CODES] — gross (`/v1`) wie klein (`/v3`). */
22
+ export declare function isPaymentErrorCode(value: unknown): value is PaymentErrorCode | Lowercase<PaymentErrorCode>;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Mehrere Zahlungen je Beleg — Fehlercode-Katalog, Zwilling von
3
+ * `functions/gemeinsam/zahlungen-core.js` ZAHLUNGS_FEHLERCODES (gleiche
4
+ * Codes, gleiche Reihenfolge).
5
+ *
6
+ * `createReceipt` und `cancelReceipt` legen sie bei jedem Fehler rund um
7
+ * `payments` (und bei den Aufrufer-Vorbedingungen wie `PAYMENTS_CONFLICT`)
8
+ * als `code` neben die Meldung; das Paket reicht sie als
9
+ * [KasseneckApiError.code] durch. **Entscheide am Code, nie am Text** — die
10
+ * deutsche Meldung darf sich aendern, der Code nicht.
11
+ *
12
+ * Schreibweise: auf `/v1`, `/v2` und intern kommen die Codes gross
13
+ * (`PAYMENTS_SUM_MISMATCH`), unter `/v3` schreibt der Rand des Backends sie
14
+ * klein (`payments_sum_mismatch`, functions/gemeinsam/api-vokabular-v3.js:
15
+ * jeder dieser Codes 1:1 in Kleinschreibung, anders als die Storno-Codes).
16
+ * [isPaymentErrorCode] erkennt beide; wer selbst vergleicht, vergleicht
17
+ * `code.toUpperCase()`.
18
+ */
19
+ export const PAYMENT_ERROR_CODES = Object.freeze([
20
+ 'PAYMENTS_INVALID', // payments ist keine Liste oder hat mehr als 20 Eintraege
21
+ 'PAYMENT_METHOD_INVALID', // Zahlart unbekannt oder mixed
22
+ 'PAYMENT_AMOUNT_INVALID', // amountCents keine Ganzzahl, 0 oder falsches Vorzeichen
23
+ 'PAYMENT_TENDERED_INVALID', // tenderedCents an Nicht-Bar-Zahlung, zu klein oder am Storno
24
+ 'PAYMENT_PROVIDER_INVALID', // Karte ohne/mit unbekanntem provider, providerPaymentId fehlt
25
+ 'PAYMENT_PROVIDER_NOT_ALLOWED', // Anbieterfelder an einer Zahlung, die weder Karte noch online ist
26
+ 'PAYMENTS_SUM_MISMATCH', // Summe != Zahlbetrag (Antwort nennt data.expectedCents)
27
+ 'PAYMENTS_DUE_NEGATIVE', // Zahlbetrag < 0 (Wertgutschein groesser als der Beleg)
28
+ 'PAYMENTS_NOT_ALLOWED', // Null-/Startbeleg mit Zahlungen, alter Storno-Weg
29
+ 'PAYMENTS_CONFLICT', // payments zusammen mit paymentMethod oder Kartenfeldern
30
+ 'PAYMENTS_REQUIRED', // /v3 ohne payments
31
+ 'PAYMENT_METHOD_NOT_SUPPORTED', // paymentMethod/Kartenfelder unter /v3
32
+ 'TIP_PAYMENT_METHOD_INVALID', // Trinkgeld-Zahlart kommt in payments nicht vor
33
+ 'TIP_PAYMENT_METHOD_REQUIRED', // mehrere Zahlarten, tip.paymentMethod fehlt
34
+ 'TIP_EXCEEDS_PAYMENT', // Trinkgeld uebersteigt die Zahlungen seiner Zahlart
35
+ 'PAYMENT_REFUND_NOT_ALLOWED', // refundOf ausserhalb eines Stornos oder kein String
36
+ 'PAYMENT_TIP_INVALID', // tipCents keine Ganzzahl, <= 0, > amountCents oder nicht am Verkauf
37
+ 'TIP_CONFLICT', // tip und payments[].tipCents zugleich
38
+ ]);
39
+ /** Erkennt einen Code aus [PAYMENT_ERROR_CODES] — gross (`/v1`) wie klein (`/v3`). */
40
+ export function isPaymentErrorCode(value) {
41
+ return typeof value === 'string' && PAYMENT_ERROR_CODES.includes(value.toUpperCase());
42
+ }