@kreiseck/kasseneck-api 0.6.45 → 0.6.49
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/README.md +95 -15
- package/dist/cjs/client/aufrufe.d.ts +1 -1
- package/dist/cjs/client/aufrufe.js +2 -0
- package/dist/cjs/client/errors.d.ts +7 -1
- package/dist/cjs/client/errors.js +8 -1
- package/dist/cjs/client/receipts.d.ts +16 -0
- package/dist/cjs/client/receipts.js +10 -0
- package/dist/cjs/client/transport.js +5 -4
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +4 -2
- package/dist/cjs/kasse/index.d.ts +1 -0
- package/dist/cjs/kasse/index.js +3 -0
- package/dist/cjs/kasse/trinkgeld.d.ts +10 -0
- package/dist/cjs/kasse/trinkgeld.js +27 -0
- package/dist/cjs/models/cancellation.d.ts +22 -0
- package/dist/cjs/models/cancellation.js +31 -1
- package/dist/cjs/models/hobex-receipt.js +9 -2
- package/dist/cjs/models/index.d.ts +1 -1
- package/dist/cjs/models/index.js +3 -1
- package/dist/cjs/models/receipt.js +3 -0
- package/dist/cjs/models/voucher.js +18 -2
- package/dist/cjs/payments/hobex-hps/connect-client.d.ts +104 -0
- package/dist/cjs/payments/hobex-hps/connect-client.js +159 -0
- package/dist/cjs/payments/hobex-hps/errors.d.ts +122 -0
- package/dist/cjs/payments/hobex-hps/errors.js +158 -0
- package/dist/cjs/payments/hobex-hps/events.d.ts +22 -0
- package/dist/cjs/payments/hobex-hps/events.js +2 -0
- package/dist/cjs/payments/hobex-hps/index.d.ts +27 -0
- package/dist/cjs/payments/hobex-hps/index.js +66 -0
- package/dist/cjs/payments/hobex-hps/outcome.d.ts +31 -0
- package/dist/cjs/payments/hobex-hps/outcome.js +7 -0
- package/dist/cjs/payments/hobex-hps/payments.d.ts +149 -0
- package/dist/cjs/payments/hobex-hps/payments.js +550 -0
- package/dist/cjs/payments/hobex-hps/receipt.d.ts +28 -0
- package/dist/cjs/payments/hobex-hps/receipt.js +60 -0
- package/dist/cjs/payments/hobex-hps/transaction-id.d.ts +65 -0
- package/dist/cjs/payments/hobex-hps/transaction-id.js +91 -0
- package/dist/cjs/payments/hobex-hps/transaction-response.d.ts +163 -0
- package/dist/cjs/payments/hobex-hps/transaction-response.js +245 -0
- package/dist/cjs/payments/hobex.js +9 -6
- package/dist/cjs/payments/index.d.ts +26 -14
- package/dist/cjs/payments/index.js +59 -15
- package/dist/cjs/printing/index.d.ts +1 -1
- package/dist/cjs/printing/index.js +2 -1
- package/dist/cjs/printing/webusb.d.ts +37 -7
- package/dist/cjs/printing/webusb.js +76 -18
- package/dist/cjs/receipt/epos.d.ts +18 -0
- package/dist/cjs/receipt/epos.js +78 -6
- package/dist/cjs/receipt/index.d.ts +1 -1
- package/dist/cjs/receipt/index.js +2 -1
- package/dist/cjs/register/index.d.ts +1 -1
- package/dist/cjs/register/index.js +2 -1
- package/dist/cjs/register/pairing.d.ts +67 -1
- package/dist/cjs/register/pairing.js +59 -3
- package/dist/esm/client/aufrufe.d.ts +1 -1
- package/dist/esm/client/aufrufe.js +2 -0
- package/dist/esm/client/errors.d.ts +7 -1
- package/dist/esm/client/errors.js +8 -1
- package/dist/esm/client/receipts.d.ts +16 -0
- package/dist/esm/client/receipts.js +10 -0
- package/dist/esm/client/transport.js +5 -4
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/kasse/index.d.ts +1 -0
- package/dist/esm/kasse/index.js +1 -0
- package/dist/esm/kasse/trinkgeld.d.ts +10 -0
- package/dist/esm/kasse/trinkgeld.js +24 -0
- package/dist/esm/models/cancellation.d.ts +22 -0
- package/dist/esm/models/cancellation.js +29 -0
- package/dist/esm/models/hobex-receipt.js +10 -3
- package/dist/esm/models/index.d.ts +1 -1
- package/dist/esm/models/index.js +1 -1
- package/dist/esm/models/receipt.js +3 -0
- package/dist/esm/models/voucher.js +18 -2
- package/dist/esm/payments/hobex-hps/connect-client.d.ts +104 -0
- package/dist/esm/payments/hobex-hps/connect-client.js +156 -0
- package/dist/esm/payments/hobex-hps/errors.d.ts +122 -0
- package/dist/esm/payments/hobex-hps/errors.js +149 -0
- package/dist/esm/payments/hobex-hps/events.d.ts +22 -0
- package/dist/esm/payments/hobex-hps/events.js +1 -0
- package/dist/esm/payments/hobex-hps/index.d.ts +27 -0
- package/dist/esm/payments/hobex-hps/index.js +26 -0
- package/dist/esm/payments/hobex-hps/outcome.d.ts +31 -0
- package/dist/esm/payments/hobex-hps/outcome.js +4 -0
- package/dist/esm/payments/hobex-hps/payments.d.ts +149 -0
- package/dist/esm/payments/hobex-hps/payments.js +547 -0
- package/dist/esm/payments/hobex-hps/receipt.d.ts +28 -0
- package/dist/esm/payments/hobex-hps/receipt.js +57 -0
- package/dist/esm/payments/hobex-hps/transaction-id.d.ts +65 -0
- package/dist/esm/payments/hobex-hps/transaction-id.js +86 -0
- package/dist/esm/payments/hobex-hps/transaction-response.d.ts +163 -0
- package/dist/esm/payments/hobex-hps/transaction-response.js +233 -0
- package/dist/esm/payments/hobex.js +9 -6
- package/dist/esm/payments/index.d.ts +26 -14
- package/dist/esm/payments/index.js +26 -14
- package/dist/esm/printing/index.d.ts +1 -1
- package/dist/esm/printing/index.js +1 -1
- package/dist/esm/printing/webusb.d.ts +37 -7
- package/dist/esm/printing/webusb.js +74 -17
- package/dist/esm/receipt/epos.d.ts +18 -0
- package/dist/esm/receipt/epos.js +76 -6
- package/dist/esm/receipt/index.d.ts +1 -1
- package/dist/esm/receipt/index.js +1 -1
- package/dist/esm/register/index.d.ts +1 -1
- package/dist/esm/register/index.js +1 -1
- package/dist/esm/register/pairing.d.ts +67 -1
- package/dist/esm/register/pairing.js +58 -3
- package/fixtures/hobex-hps-codes.json +67 -0
- package/fixtures/oberflaeche.json +3 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -167,6 +167,38 @@ sich nicht stornieren, ein voll stornierter Beleg nicht noch einmal. Am
|
|
|
167
167
|
gelesenen Original liefert `remainingQuantities(receipt)` die Reste vorab (für
|
|
168
168
|
den Storno-Dialog); die Wahrheit hat der Server.
|
|
169
169
|
|
|
170
|
+
**Fehler entscheidet man am Code, nicht am Text.** Jeder fachliche Fehler von
|
|
171
|
+
`cancelReceipt` trägt `KasseneckApiError.code` aus `CANCELLATION_ERROR_CODES`
|
|
172
|
+
(z. B. `bereits_storniert`, `menge_ueber_rest`, `nur_eigene_belege`). Die
|
|
173
|
+
deutsche Meldung (`serverMessage`) ist Anzeige und darf sich ändern.
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
import { isKasseneckApiError, isCancellationErrorCode } from '@kreiseck/kasseneck-api';
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
await api.cancelReceipt({ receipt: beleg, reason: 'fehleingabe' });
|
|
180
|
+
} catch (fehler) {
|
|
181
|
+
if (isKasseneckApiError(fehler) && isCancellationErrorCode(fehler.code)) {
|
|
182
|
+
switch (fehler.code) {
|
|
183
|
+
case 'bereits_storniert': // Beleg im Dialog als „storniert" zeigen, Knopf sperren
|
|
184
|
+
case 'menge_ueber_rest': // Restmengen neu laden (jemand war schneller)
|
|
185
|
+
case 'nur_eigene_belege': // Chef holen
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
throw fehler;
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Gutscheine.** Ein Wertgutschein wird nur beim Vollstorno (ohne `items`)
|
|
194
|
+
gespiegelt — er ist unteilbar. Ein Rabattgutschein ist am Original bereits in
|
|
195
|
+
den Umsatz eingerechnet; **jeder** Storno nimmt ihn anteilig der stornierten
|
|
196
|
+
Menge zurück: bei 3 Stück à 10 € mit 6 € Rabatt sind 8 € je Stück Entgelt, der
|
|
197
|
+
Storno-Beleg trägt dann „−10,00" plus eine Zeile „Gutschein-Ausgleich +2,00".
|
|
198
|
+
Was ein Storno gewährt hat, steht am Eintrag in `receipt.cancellations[]` als
|
|
199
|
+
`promoAdjustmentCents` (Cent je Steuertopf) — die Kasse kann es im Dialog
|
|
200
|
+
zeigen, rechnen muss sie nichts.
|
|
201
|
+
|
|
170
202
|
## Unterpfade
|
|
171
203
|
|
|
172
204
|
| Unterpfad | Inhalt |
|
|
@@ -174,7 +206,7 @@ den Storno-Dialog); die Wahrheit hat der Server.
|
|
|
174
206
|
| `@kreiseck/kasseneck-api` | Endpunkte, Anmeldung, Transport, Modelle, Enums, Fehler — alles, was mit dem Backend spricht. |
|
|
175
207
|
| `…/receipt` | Beleg-Layout als Datenmodell (framework-frei) und die Brücke zu ESC/POS. |
|
|
176
208
|
| `…/printing` | ESC/POS-Erzeugung: Bytefolgen für Bondrucker, ohne jeden Transport. |
|
|
177
|
-
| `…/payments` | Stripe-Zahllinks
|
|
209
|
+
| `…/payments` | Stripe-Zahllinks, Hobex-Cloud (beides HTTP-Endpunkte des Backends) und Hobex **HPS** über **Kasseneck Connect** (lokaler Geräte-Agent, spricht mit dem Terminal). |
|
|
178
210
|
| `…/register` | Anmeldung der Browser-Kasse: Gerät koppeln und entkoppeln, Benutzer auflisten, per PIN anmelden, Sitzung erneuern und beenden. |
|
|
179
211
|
| `…/kasse` | Kachel-Kasse: Kassen-Einstellungen (betriebsweit / je Gerät), Artikelgruppen und Artikel für Kacheln, Rabattverteilung je Steuersatz, Reichweiten der Kassen-Rechte |
|
|
180
212
|
| `…/react` | Dünner React-Adapter, der ein Beleg-Layout zeichnet. Braucht React. |
|
|
@@ -182,16 +214,40 @@ den Storno-Dialog); die Wahrheit hat der Server.
|
|
|
182
214
|
|
|
183
215
|
So zieht sich niemand den React-Adapter in ein Node-Programm.
|
|
184
216
|
|
|
185
|
-
##
|
|
217
|
+
## Hobex HPS über Kasseneck Connect
|
|
218
|
+
|
|
219
|
+
Ein Browser hat weiterhin keine rohen TCP-Sockets — ein **direkter**
|
|
220
|
+
Terminal-Kontakt wie beim Flutter-Paket `kasseneck_api` (`HpsClient`) bleibt
|
|
221
|
+
deshalb außerhalb der Reichweite dieses Pakets. **Kasseneck Connect** ist aber
|
|
222
|
+
ein lokaler Geräte-Agent mit gewöhnlicher HTTP-Schnittstelle, der für die Kasse
|
|
223
|
+
mit dem Terminal spricht — und darüber geht es:
|
|
186
224
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
sind Android-SDKs. Ein Browser kann das nicht, und kein Bündler ändert daran
|
|
190
|
-
etwas. Wer diese Terminals braucht, nimmt das Flutter-Paket `kasseneck_api`.
|
|
225
|
+
```ts
|
|
226
|
+
import { createHpsConnectClient, createHpsPayments } from '@kreiseck/kasseneck-api/payments';
|
|
191
227
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
228
|
+
const client = createHpsConnectClient({ token: kopplungsToken });
|
|
229
|
+
const zahlweg = createHpsPayments(client, { host: '192.168.1.50', tid: '3600335' });
|
|
230
|
+
|
|
231
|
+
const ergebnis = await zahlweg.pay({ amountCents: 1050 });
|
|
232
|
+
// ergebnis.outcome: 'approved' | 'declined' | 'unresolved' — nie geraten.
|
|
233
|
+
// ergebnis.transactionId ist IMMER gesetzt, auch bei 'unresolved'.
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Der Ausgang ist immer einer von drei: `approved`, `declined` (beweisbar nichts
|
|
237
|
+
belastet) oder `unresolved` (Ausgang unbekannt, eine Wiederholung könnte ein
|
|
238
|
+
zweites Mal belasten). Was das bedeutet und warum es so gebaut ist, steht in
|
|
239
|
+
`src/payments/hobex-hps/payments.ts` — dort ist die Dokumentation der Maßstab,
|
|
240
|
+
nicht dieses README.
|
|
241
|
+
|
|
242
|
+
**Nur `pay` — bewusst kein `refund`/`cancel`.** Kasseneck Connect exponiert
|
|
243
|
+
dafür (noch) keinen Endpunkt; eine Gutschrift oder ein Storno am HPS-Terminal
|
|
244
|
+
braucht weiterhin die Flutter-App. **myPOS** und **SumUp** bleiben
|
|
245
|
+
Android-SDKs ohne Entsprechung hier.
|
|
246
|
+
|
|
247
|
+
## Was hier grundsätzlich nicht dazugehört
|
|
248
|
+
|
|
249
|
+
Die Druckeransteuerung selbst (dieses Paket erzeugt die Bytes, es verschickt
|
|
250
|
+
sie nicht), Firmenlogos und Rasterbilder, und die PDF-Erzeugung.
|
|
195
251
|
|
|
196
252
|
## Entwicklung
|
|
197
253
|
|
|
@@ -199,28 +255,52 @@ PDF-Erzeugung.
|
|
|
199
255
|
npm test # Testsuite in drei Zeitzonen (Wien, UTC, Kiritimati)
|
|
200
256
|
npm run build # ESM- und CJS-Bau nach dist/, inkl. Prüfung der exports
|
|
201
257
|
npm run check:consumer # baut den Tarball und übersetzt zwei Verbraucher (CJS/ESM)
|
|
258
|
+
npm run check:erreichbar # fragt die öffentliche Adresse: antwortet dort zu jedem Aufruf eine Function?
|
|
202
259
|
```
|
|
203
260
|
|
|
204
261
|
Die drei Zeitzonen sind kein Übereifer: Zeitfehler sind auf einer Wiener
|
|
205
262
|
Maschine zufällig richtig. Belegzeiten werden konsequent als **Wiener
|
|
206
263
|
Wanduhrzeit** gedeutet (`parseServerTimeStamp`), nie über `new Date(text)`.
|
|
207
264
|
|
|
265
|
+
### `check:erreichbar` — spricht als einzige mit `api.kasseneck.at`
|
|
266
|
+
|
|
267
|
+
Testsuite und `check:consumer` laufen gegen Attrappen bzw. gegen den Tarball;
|
|
268
|
+
keine von beiden setzt je einen Aufruf ab. Fehlt einem Aufruf die
|
|
269
|
+
Hosting-Weiterleitung, liefert die veröffentlichte Adresse die
|
|
270
|
+
HTML-Auffangseite statt der Function — und das sieht keine Attrappe.
|
|
271
|
+
|
|
272
|
+
Die Prüfung braucht **keine Zugangsdaten**. Ein Aufruf ohne Anmeldung
|
|
273
|
+
antwortet, wenn dort eine Function steht, mit
|
|
274
|
+
`{"status":"error","message":"Ungültiger Request: Authorization key erwartet."}`.
|
|
275
|
+
Genau das ist der Beweis: Der Aufruf wurde angenommen und die Anmeldung
|
|
276
|
+
geprüft. Eine HTML-Seite oder ein 404 ist der Beweis, dass dort keine Function
|
|
277
|
+
steht. Deshalb prüft das Skript auf ein `status`-Feld und nicht auf Erfolg.
|
|
278
|
+
|
|
279
|
+
Bewusst außerhalb von `npm test`: Sie braucht Netz. Ist keines da, sagt sie es
|
|
280
|
+
und endet mit 0. Aufrufe, die unter `/v1` absichtlich keine Weiterleitung
|
|
281
|
+
haben — der Kassen-Weg über `kasse.kasseneck.at/api`, die Aufrufe mit
|
|
282
|
+
Firebase-ID-Token — stehen mit Grund in `scripts/erreichbarkeit-ausnahmen.json`.
|
|
283
|
+
Wird eine Ausnahme erreichbar, schlägt die Prüfung an: Sonst sänke die Zahl nie.
|
|
284
|
+
|
|
208
285
|
## Vertragsdateien für die Zwillinge
|
|
209
286
|
|
|
210
287
|
Dieses Paket ist die Quelle für das Dart-Paket `kasseneck_api` und den
|
|
211
|
-
Backend-Validator `kasse-settings-core.js`.
|
|
212
|
-
im Tarball mit und sagen in Maschinenform, worauf sich
|
|
288
|
+
Backend-Validator `kasse-settings-core.js`. Drei Dateien in `fixtures/` reisen
|
|
289
|
+
im Tarball mit und sagen in Maschinenform, worauf sich beide Seiten geeinigt haben:
|
|
213
290
|
|
|
214
291
|
| Datei | Inhalt |
|
|
215
292
|
|---|---|
|
|
216
293
|
| `kasse-settings-standard.json` | Feldnamen und Standardwerte der Kassen-Einstellungen |
|
|
217
294
|
| `oberflaeche.json` | Aufrufnamen, Enum-Werte, Rechte-Schlüssel, Tasten-Aktionen |
|
|
295
|
+
| `hobex-hps-codes.json` | Gemessene HPS-Ergebniscodes, ihre Bedeutung und ob sie einen Ausgang festschreiben — der Vertrag hinter `.../payments/hobex-hps`s `isConclusive`. |
|
|
218
296
|
|
|
219
|
-
|
|
220
|
-
und nie von Hand geändert; die CI prüft
|
|
297
|
+
Alle drei werden erzeugt (`npm run fixtures:kasse`, `npm run fixtures:oberflaeche`,
|
|
298
|
+
`npm run fixtures:hobex-hps-codes`) und nie von Hand geändert; die CI prüft
|
|
299
|
+
nach jedem Lauf, dass sie zum Code passen.
|
|
221
300
|
|
|
222
|
-
`oberflaeche.json`
|
|
223
|
-
|
|
301
|
+
`oberflaeche.json` und `hobex-hps-codes.json` tragen die Paketversion. **Nach
|
|
302
|
+
jedem `npm version` müssen deshalb alle drei Dateien neu erzeugt und
|
|
303
|
+
mitcommittet werden**, sonst wird die CI rot.
|
|
224
304
|
|
|
225
305
|
## Lizenz
|
|
226
306
|
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* umhuellt, muss ihn weiterhin absetzen koennen.
|
|
14
14
|
*/
|
|
15
15
|
import type { TransportBodyFields } from './transport.js';
|
|
16
|
-
export declare const AUFRUFE: readonly ["cancelReceipt", "createPaymentLinkStripe", "createPrintJob", "createReceipt", "downloadDailyReport", "downloadReport", "endRegisterSession", "financeWebService", "generateFullReceiptId", "getFirstReceiptDate", "getKasseSettings", "getPrintJob", "getReceipt", "hobexPayApi", "hobexRefundApi", "listMyArticleGroups", "listMyArticles", "listMyCashregisters", "listMyPrinters", "listMyReceipts", "listRegisterUsersForDevice", "pairRegisterDevice", "registerPinLogin", "registerUserLogin", "renewRegisterSession", "setMyKasseSettings", "setMyRegisterDeviceSettings", "stripeCaptureIntent", "unpairRegisterDevice"];
|
|
16
|
+
export declare const AUFRUFE: readonly ["cancelReceipt", "createPaymentLinkStripe", "createPrintJob", "createReceipt", "downloadDailyReport", "downloadReport", "endRegisterSession", "financeWebService", "generateFullReceiptId", "getFirstReceiptDate", "getKasseSettings", "getPrintJob", "getReceipt", "hobexPayApi", "hobexRefundApi", "listMyArticleGroups", "listMyArticles", "listMyCashregisters", "listMyPrinters", "listMyReceipts", "listMyTipRecipients", "listRegisterUsersForDevice", "listRegisterSessionsForDevice", "pairRegisterDevice", "registerPinLogin", "registerUserLogin", "renewRegisterSession", "setMyKasseSettings", "setMyRegisterDeviceSettings", "stripeCaptureIntent", "unpairRegisterDevice"];
|
|
17
17
|
export type Aufruf = typeof AUFRUFE[number];
|
|
18
18
|
/** Wie [KasseneckTransport], nur mit bekanntem Aufrufnamen. Nicht exportiert nach aussen. */
|
|
19
19
|
export type InternerTransport = <T = unknown>(functionName: Aufruf, params?: Record<string, unknown>, extraBodyFields?: TransportBodyFields, secretParams?: readonly string[]) => Promise<T>;
|
|
@@ -76,7 +76,13 @@ export declare class KasseneckApiError extends Error {
|
|
|
76
76
|
readonly functionName: string;
|
|
77
77
|
/** Meldung des Backends, unveraendert (`message` aus der Huelle). */
|
|
78
78
|
readonly serverMessage: string;
|
|
79
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Stabiler Fehlercode des Backends (`code` aus der Huelle), wenn der
|
|
81
|
+
* Endpunkt einen legt — heute `cancelReceipt` (siehe CANCELLATION_ERROR_CODES).
|
|
82
|
+
* Daran entscheiden, nie an [serverMessage]: der Text darf sich aendern.
|
|
83
|
+
*/
|
|
84
|
+
readonly code: string | undefined;
|
|
85
|
+
constructor(functionName: string, serverMessage: string, code?: string);
|
|
80
86
|
}
|
|
81
87
|
/** Warum die Antwort keine verwertbare Huelle war. */
|
|
82
88
|
export type HttpFailureReason = 'server-error' | 'empty-body' | 'not-json' | 'missing-status';
|
|
@@ -101,10 +101,17 @@ class KasseneckApiError extends Error {
|
|
|
101
101
|
functionName;
|
|
102
102
|
/** Meldung des Backends, unveraendert (`message` aus der Huelle). */
|
|
103
103
|
serverMessage;
|
|
104
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Stabiler Fehlercode des Backends (`code` aus der Huelle), wenn der
|
|
106
|
+
* Endpunkt einen legt — heute `cancelReceipt` (siehe CANCELLATION_ERROR_CODES).
|
|
107
|
+
* Daran entscheiden, nie an [serverMessage]: der Text darf sich aendern.
|
|
108
|
+
*/
|
|
109
|
+
code;
|
|
110
|
+
constructor(functionName, serverMessage, code) {
|
|
105
111
|
super(`${functionName} fehlgeschlagen: ${serverMessage}`);
|
|
106
112
|
this.functionName = functionName;
|
|
107
113
|
this.serverMessage = serverMessage;
|
|
114
|
+
this.code = code;
|
|
108
115
|
}
|
|
109
116
|
}
|
|
110
117
|
exports.KasseneckApiError = KasseneckApiError;
|
|
@@ -54,6 +54,22 @@ export interface TipOptions {
|
|
|
54
54
|
paymentMethod?: KeckPaymentMethod | KeckPaymentMethodKey;
|
|
55
55
|
/** Empfaenger; ohne Angabe der angemeldete Kassen-Benutzer. Summe der cents = cents. */
|
|
56
56
|
recipients?: TipRecipientShare[];
|
|
57
|
+
/**
|
|
58
|
+
* Hat der Empfaenger das Geld schon? `true` = ja (Bargeld mitgenommen,
|
|
59
|
+
* Kartentrinkgeld sofort aus der Lade ausgezahlt), `false` = der Betrieb
|
|
60
|
+
* behaelt es und schuldet es.
|
|
61
|
+
*
|
|
62
|
+
* Entscheidend ist NICHT die Zahlart, sondern der Besitz -- § 2j Abs 2 AVRAG
|
|
63
|
+
* kennt beide Faelle. Ohne Angabe gilt die Voreinstellung des Betriebs (bar:
|
|
64
|
+
* schon erhalten, bargeldlos: einbehalten); diese Angabe braucht es nur fuer
|
|
65
|
+
* die Ausnahme.
|
|
66
|
+
*
|
|
67
|
+
* NUR mit dem Recht `tipAssign` bei persoenlicher Anmeldung: das Merkmal
|
|
68
|
+
* entscheidet, ob der Betrieb Geld schuldet, und gewoehnliches Personal soll
|
|
69
|
+
* das nicht am Geraet umstellen koennen. Ueber einen Geraete-API-Schluessel
|
|
70
|
+
* (ohne angemeldeten Kassen-Benutzer) gilt die Einschraenkung nicht.
|
|
71
|
+
*/
|
|
72
|
+
sofortErhalten?: boolean;
|
|
57
73
|
}
|
|
58
74
|
export interface TipRecipientShare {
|
|
59
75
|
registerUserId: string;
|
|
@@ -399,6 +399,16 @@ function gepruefterTip(tip) {
|
|
|
399
399
|
const nutzlast = { cents: tip.cents };
|
|
400
400
|
if (tip.paymentMethod != null)
|
|
401
401
|
nutzlast['paymentMethod'] = gepruefteZahlungsart(tip.paymentMethod);
|
|
402
|
+
// Nur mitschicken, wenn gesetzt: fehlt das Feld, entscheidet die
|
|
403
|
+
// Voreinstellung des Betriebs. Ein `false` waere dort eine Aussage, kein
|
|
404
|
+
// Weglassen. Der Wortlaut des Fehlers ist der des Backends
|
|
405
|
+
// (tip-core.normalizeTip) -- wer ihn hier sieht, sieht denselben Satz.
|
|
406
|
+
if (tip.sofortErhalten != null) {
|
|
407
|
+
if (typeof tip.sofortErhalten !== 'boolean') {
|
|
408
|
+
throw eingabefehler('Trinkgeld: sofortErhalten muss true oder false sein.');
|
|
409
|
+
}
|
|
410
|
+
nutzlast['sofortErhalten'] = tip.sofortErhalten;
|
|
411
|
+
}
|
|
402
412
|
if (tip.recipients != null) {
|
|
403
413
|
if (!Array.isArray(tip.recipients) || tip.recipients.length === 0) {
|
|
404
414
|
throw eingabefehler('Trinkgeld: recipients darf nicht leer sein.');
|
|
@@ -181,7 +181,7 @@ function jsonAuswerten(text, functionName, statusCode, inhaltstyp) {
|
|
|
181
181
|
}
|
|
182
182
|
// Alles, was nicht ausdruecklich Erfolg ist, gilt als fachlicher Fehler —
|
|
183
183
|
// ein unbekannter Statuswert darf nie stillschweigend als Erfolg durchgehen.
|
|
184
|
-
throw fachfehler(functionName, huelle.message);
|
|
184
|
+
throw fachfehler(functionName, huelle.message, huelle.code);
|
|
185
185
|
}
|
|
186
186
|
/**
|
|
187
187
|
* Auswertung des Binaerwegs. Der Kern der Zusage: **ein Aufrufer bekommt nie
|
|
@@ -227,7 +227,7 @@ function pdfAuswerten(bytes, functionName, statusCode, inhaltstyp) {
|
|
|
227
227
|
}
|
|
228
228
|
// Derselbe fachliche Fehler wie auf dem JSON-Weg — fuer den Aufrufer macht
|
|
229
229
|
// es keinen Unterschied, ob er ein PDF oder eine Nutzlast erwartet hat.
|
|
230
|
-
throw fachfehler(functionName, huelle.message);
|
|
230
|
+
throw fachfehler(functionName, huelle.message, huelle.code);
|
|
231
231
|
}
|
|
232
232
|
/** `%PDF` am Anfang — die Kennung jeder PDF-Datei. */
|
|
233
233
|
function istPdf(bytes) {
|
|
@@ -240,9 +240,10 @@ function alsHuelle(wert) {
|
|
|
240
240
|
}
|
|
241
241
|
return wert;
|
|
242
242
|
}
|
|
243
|
-
function fachfehler(functionName, message) {
|
|
243
|
+
function fachfehler(functionName, message, code) {
|
|
244
244
|
const meldung = typeof message === 'string' && message.trim() ? message : 'Unbekannter Fehler';
|
|
245
|
-
|
|
245
|
+
// Nur ein Text zaehlt als Code -- alles andere waere ein geratener Vertrag.
|
|
246
|
+
return new errors_js_1.KasseneckApiError(functionName, meldung, typeof code === 'string' && code ? code : undefined);
|
|
246
247
|
}
|
|
247
248
|
/**
|
|
248
249
|
* Nutzlast aus Auth- und Aufruferparametern. Auth-Parameter bilden die
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { ReceiptType, type ReceiptTypeKey, VatRate, type VatRateKey, KeckPaymentMethod, type KeckPaymentMethodKey, CreditCardProvider, type CreditCardProviderKey, VoucherType, type VoucherTypeKey, VoucherAction, type VoucherActionKey, StripeLinkMode, type StripeLinkModeKey, } from './enums/index.js';
|
|
2
|
-
export { type ReceiptItem, type ReceiptItemPayload, type ReceiptItemPayloadRead, toReceiptItemPayload, fromReceiptItemPayload, receiptItemTotalCents, receiptItemIsValid, negateReceiptItem, type TipRecipient, isTipItem, type Voucher, type VoucherPayload, toVoucherPayload, fromVoucherPayload, voucherIsValid, type Receipt, type ReceiptPayload, type ReceiptPayloadRead, toReceiptPayload, fromReceiptPayload, receiptSubSumCents, receiptSumCents, type CancellationOf, type CancellationItem, type Cancellation, type CancellationReason, CANCELLATION_REASONS, CANCELLATION_RESERVATION_MS, isCancellationReason, remainingQuantities, type ReceiptCompany, type ReceiptCompanyPayload, fromReceiptCompanyPayload, receiptCompanyTaxInfo, type Cashregister, type CashregisterOnboarding, type CashregisterPayload, type CashregisterOnboardingPayload, fromCashregisterPayload, type ReceiptSummary, type ReceiptSummaryPayload, fromReceiptSummaryPayload, type ZeroKind, ZERO_KINDS, istZeroKind, type ReportMonth, reportMonthFromDate, previousReportMonth, nextReportMonth, reportMonthKey, reportMonthReadable, type StripeUrlSession, type StripeUrlSessionPayload, toStripeUrlSessionPayload, fromStripeUrlSessionPayload, type HobexReceipt, type HobexReceiptPayload, toHobexReceiptPayload, fromHobexReceiptPayload, hobexReceiptToCardPaymentData, hobexReceiptNeedsSignature, } from './models/index.js';
|
|
2
|
+
export { type ReceiptItem, type ReceiptItemPayload, type ReceiptItemPayloadRead, toReceiptItemPayload, fromReceiptItemPayload, receiptItemTotalCents, receiptItemIsValid, negateReceiptItem, type TipRecipient, isTipItem, type Voucher, type VoucherPayload, toVoucherPayload, fromVoucherPayload, voucherIsValid, type Receipt, type ReceiptPayload, type ReceiptPayloadRead, toReceiptPayload, fromReceiptPayload, receiptSubSumCents, receiptSumCents, type CancellationOf, type CancellationItem, type Cancellation, type CancellationReason, type CancellationErrorCode, CANCELLATION_REASONS, CANCELLATION_ERROR_CODES, CANCELLATION_RESERVATION_MS, isCancellationReason, isCancellationErrorCode, remainingQuantities, type ReceiptCompany, type ReceiptCompanyPayload, fromReceiptCompanyPayload, receiptCompanyTaxInfo, type Cashregister, type CashregisterOnboarding, type CashregisterPayload, type CashregisterOnboardingPayload, fromCashregisterPayload, type ReceiptSummary, type ReceiptSummaryPayload, fromReceiptSummaryPayload, type ZeroKind, ZERO_KINDS, istZeroKind, type ReportMonth, reportMonthFromDate, previousReportMonth, nextReportMonth, reportMonthKey, reportMonthReadable, type StripeUrlSession, type StripeUrlSessionPayload, toStripeUrlSessionPayload, fromStripeUrlSessionPayload, type HobexReceipt, type HobexReceiptPayload, toHobexReceiptPayload, fromHobexReceiptPayload, hobexReceiptToCardPaymentData, hobexReceiptNeedsSignature, } from './models/index.js';
|
|
3
3
|
export { type AuthCredentials, type KasseneckAuth, type ApiKeyAuthOptions, type RegisterUserAuthOptions, apiKeyAuth, registerUserAuth, DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, type HttpResponseLike, type HttpRequestInit, type FetchLike, type TransportOptions, type TransportBodyFields, type KasseneckTransport, type KasseneckBinaryTransport, AUFRUFE, type Aufruf, createTransport, createBinaryTransport, KasseneckApiError, KasseneckAuthError, KasseneckHttpError, KasseneckNetworkError, KasseneckValidationError, type ValidationScope, type KasseneckError, type HttpFailureReason, type CauseDigest, isKasseneckApiError, isKasseneckAuthError, isKasseneckHttpError, isKasseneckNetworkError, isKasseneckValidationError, type ReceiptCommonOptions, type SellReceiptOptions, type TipOptions, type TipRecipientShare, type CancelReceiptOptions, type CancelReceiptResult, type CreateCancelReceiptOptions, type ReceiptWithCompany, sellReceipt, sellReceiptWithCompany, cancelReceipt, createCancelReceipt, zeroReceipt, getReceipt, getReceiptWithCompany, generateFullReceiptId, getFirstReceiptDate, listMyReceipts, type ListMyReceiptsOptions, type ReceiptList, type ReceiptListStats, listMyCashregisters, checkVoucherCombinationError, downloadDailyReport, downloadMonthlyReport, type CashboxStatus, type SignatureStatus, getCashboxStatus, getSignatureStatus, type KasseneckApi, createKasseneckApi, } from './client/index.js';
|
|
4
4
|
export { parseServerTimeStamp, toViennaWallClock, type ViennaWallClock } from './vienna-time.js';
|
|
5
5
|
export { type KasseSettingsBetrieb, type KasseSettingsGeraet, type KasseSettings, type ArticleGroup, type KasseArtikel, KASSE_BETRIEB_STANDARD, KASSE_GERAET_STANDARD, mergeKasseSettings, fromArticleGroupPayload, fromKasseArtikelPayload, listMyArticleGroups, listMyArticles, getKasseSettings, setMyKasseSettings, setMyRegisterDeviceSettings, verteileRabatt, cancelScopeOf, receiptsScopeOf, } from './kasse/index.js';
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.receiptsScopeOf = exports.cancelScopeOf = exports.verteileRabatt = exports.setMyRegisterDeviceSettings = exports.setMyKasseSettings = exports.getKasseSettings = exports.listMyArticles = exports.listMyArticleGroups = exports.fromKasseArtikelPayload = exports.fromArticleGroupPayload = exports.mergeKasseSettings = exports.KASSE_GERAET_STANDARD = exports.KASSE_BETRIEB_STANDARD = exports.toViennaWallClock = exports.parseServerTimeStamp = exports.createKasseneckApi = exports.getSignatureStatus = exports.getCashboxStatus = exports.downloadMonthlyReport = exports.downloadDailyReport = exports.checkVoucherCombinationError = exports.listMyCashregisters = exports.listMyReceipts = exports.getFirstReceiptDate = exports.generateFullReceiptId = exports.getReceiptWithCompany = exports.getReceipt = exports.zeroReceipt = exports.createCancelReceipt = exports.cancelReceipt = exports.sellReceiptWithCompany = exports.sellReceipt = exports.isKasseneckValidationError = exports.isKasseneckNetworkError = exports.isKasseneckHttpError = exports.isKasseneckAuthError = exports.isKasseneckApiError = exports.KasseneckValidationError = exports.KasseneckNetworkError = exports.KasseneckHttpError = void 0;
|
|
3
|
+
exports.createBinaryTransport = exports.createTransport = exports.AUFRUFE = exports.DEFAULT_TIMEOUT_MS = exports.DEFAULT_BASE_URL = exports.registerUserAuth = exports.apiKeyAuth = exports.hobexReceiptNeedsSignature = exports.hobexReceiptToCardPaymentData = exports.fromHobexReceiptPayload = exports.toHobexReceiptPayload = exports.fromStripeUrlSessionPayload = exports.toStripeUrlSessionPayload = exports.reportMonthReadable = exports.reportMonthKey = exports.nextReportMonth = exports.previousReportMonth = exports.reportMonthFromDate = exports.istZeroKind = exports.ZERO_KINDS = exports.fromReceiptSummaryPayload = exports.fromCashregisterPayload = exports.receiptCompanyTaxInfo = exports.fromReceiptCompanyPayload = exports.remainingQuantities = exports.isCancellationErrorCode = exports.isCancellationReason = exports.CANCELLATION_RESERVATION_MS = exports.CANCELLATION_ERROR_CODES = exports.CANCELLATION_REASONS = exports.receiptSumCents = exports.receiptSubSumCents = exports.fromReceiptPayload = exports.toReceiptPayload = exports.voucherIsValid = exports.fromVoucherPayload = exports.toVoucherPayload = exports.isTipItem = exports.negateReceiptItem = exports.receiptItemIsValid = exports.receiptItemTotalCents = exports.fromReceiptItemPayload = exports.toReceiptItemPayload = exports.StripeLinkMode = exports.VoucherAction = exports.VoucherType = exports.CreditCardProvider = exports.KeckPaymentMethod = exports.VatRate = exports.ReceiptType = void 0;
|
|
4
|
+
exports.receiptsScopeOf = exports.cancelScopeOf = exports.verteileRabatt = exports.setMyRegisterDeviceSettings = exports.setMyKasseSettings = exports.getKasseSettings = exports.listMyArticles = exports.listMyArticleGroups = exports.fromKasseArtikelPayload = exports.fromArticleGroupPayload = exports.mergeKasseSettings = exports.KASSE_GERAET_STANDARD = exports.KASSE_BETRIEB_STANDARD = exports.toViennaWallClock = exports.parseServerTimeStamp = exports.createKasseneckApi = exports.getSignatureStatus = exports.getCashboxStatus = exports.downloadMonthlyReport = exports.downloadDailyReport = exports.checkVoucherCombinationError = exports.listMyCashregisters = exports.listMyReceipts = exports.getFirstReceiptDate = exports.generateFullReceiptId = exports.getReceiptWithCompany = exports.getReceipt = exports.zeroReceipt = exports.createCancelReceipt = exports.cancelReceipt = exports.sellReceiptWithCompany = exports.sellReceipt = exports.isKasseneckValidationError = exports.isKasseneckNetworkError = exports.isKasseneckHttpError = exports.isKasseneckAuthError = exports.isKasseneckApiError = exports.KasseneckValidationError = exports.KasseneckNetworkError = exports.KasseneckHttpError = exports.KasseneckAuthError = exports.KasseneckApiError = void 0;
|
|
5
5
|
var index_js_1 = require("./enums/index.js");
|
|
6
6
|
Object.defineProperty(exports, "ReceiptType", { enumerable: true, get: function () { return index_js_1.ReceiptType; } });
|
|
7
7
|
Object.defineProperty(exports, "VatRate", { enumerable: true, get: function () { return index_js_1.VatRate; } });
|
|
@@ -25,8 +25,10 @@ Object.defineProperty(exports, "fromReceiptPayload", { enumerable: true, get: fu
|
|
|
25
25
|
Object.defineProperty(exports, "receiptSubSumCents", { enumerable: true, get: function () { return index_js_2.receiptSubSumCents; } });
|
|
26
26
|
Object.defineProperty(exports, "receiptSumCents", { enumerable: true, get: function () { return index_js_2.receiptSumCents; } });
|
|
27
27
|
Object.defineProperty(exports, "CANCELLATION_REASONS", { enumerable: true, get: function () { return index_js_2.CANCELLATION_REASONS; } });
|
|
28
|
+
Object.defineProperty(exports, "CANCELLATION_ERROR_CODES", { enumerable: true, get: function () { return index_js_2.CANCELLATION_ERROR_CODES; } });
|
|
28
29
|
Object.defineProperty(exports, "CANCELLATION_RESERVATION_MS", { enumerable: true, get: function () { return index_js_2.CANCELLATION_RESERVATION_MS; } });
|
|
29
30
|
Object.defineProperty(exports, "isCancellationReason", { enumerable: true, get: function () { return index_js_2.isCancellationReason; } });
|
|
31
|
+
Object.defineProperty(exports, "isCancellationErrorCode", { enumerable: true, get: function () { return index_js_2.isCancellationErrorCode; } });
|
|
30
32
|
Object.defineProperty(exports, "remainingQuantities", { enumerable: true, get: function () { return index_js_2.remainingQuantities; } });
|
|
31
33
|
Object.defineProperty(exports, "fromReceiptCompanyPayload", { enumerable: true, get: function () { return index_js_2.fromReceiptCompanyPayload; } });
|
|
32
34
|
Object.defineProperty(exports, "receiptCompanyTaxInfo", { enumerable: true, get: function () { return index_js_2.receiptCompanyTaxInfo; } });
|
|
@@ -9,3 +9,4 @@ export { getKasseSettings, setMyKasseSettings, setMyRegisterDeviceSettings } fro
|
|
|
9
9
|
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
|
+
export { listMyTipRecipients } from './trinkgeld.js';
|
package/dist/cjs/kasse/index.js
CHANGED
|
@@ -1,6 +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.listMyTipRecipients = void 0;
|
|
4
5
|
/**
|
|
5
6
|
* Kachel-Kasse: Einstellungen, Artikelgruppen/Artikel fuer Kacheln,
|
|
6
7
|
* Rabattverteilung. Die Aufrufe heissen 1:1 wie die Backend-Functions
|
|
@@ -65,3 +66,5 @@ var drucker_js_1 = require("./drucker.js");
|
|
|
65
66
|
Object.defineProperty(exports, "listMyPrinters", { enumerable: true, get: function () { return drucker_js_1.listMyPrinters; } });
|
|
66
67
|
Object.defineProperty(exports, "createPrintJob", { enumerable: true, get: function () { return drucker_js_1.createPrintJob; } });
|
|
67
68
|
Object.defineProperty(exports, "getPrintJob", { enumerable: true, get: function () { return drucker_js_1.getPrintJob; } });
|
|
69
|
+
var trinkgeld_js_1 = require("./trinkgeld.js");
|
|
70
|
+
Object.defineProperty(exports, "listMyTipRecipients", { enumerable: true, get: function () { return trinkgeld_js_1.listMyTipRecipients; } });
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { InternerTransport } from '../client/aufrufe.js';
|
|
2
|
+
import type { TipRecipient } from '../models/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Die Personen, denen dieser Aufrufer Trinkgeld zuweisen kann.
|
|
5
|
+
*
|
|
6
|
+
* Es ist **dieselbe Menge**, die `createReceipt` akzeptiert — wer hier steht,
|
|
7
|
+
* wird beim Verkauf nicht zurueckgewiesen. Ist ein Kassen-Benutzer ohne das
|
|
8
|
+
* Recht `tipAssign` angemeldet, steht nur er selbst darin.
|
|
9
|
+
*/
|
|
10
|
+
export declare function listMyTipRecipients(rufen: InternerTransport): Promise<TipRecipient[]>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listMyTipRecipients = listMyTipRecipients;
|
|
4
|
+
const errors_js_1 = require("../client/errors.js");
|
|
5
|
+
/**
|
|
6
|
+
* Die Personen, denen dieser Aufrufer Trinkgeld zuweisen kann.
|
|
7
|
+
*
|
|
8
|
+
* Es ist **dieselbe Menge**, die `createReceipt` akzeptiert — wer hier steht,
|
|
9
|
+
* wird beim Verkauf nicht zurueckgewiesen. Ist ein Kassen-Benutzer ohne das
|
|
10
|
+
* Recht `tipAssign` angemeldet, steht nur er selbst darin.
|
|
11
|
+
*/
|
|
12
|
+
async function listMyTipRecipients(rufen) {
|
|
13
|
+
const daten = await rufen('listMyTipRecipients');
|
|
14
|
+
const roh = daten?.recipients;
|
|
15
|
+
if (!Array.isArray(roh)) {
|
|
16
|
+
// Keine Liste ist etwas anderes als eine leere Liste: „noch niemand
|
|
17
|
+
// angelegt" darf nicht aussehen wie „Antwort kaputt".
|
|
18
|
+
throw new errors_js_1.KasseneckValidationError('listMyTipRecipients', 'Antwort enthaelt keine Liste (data.recipients fehlt)', 'response');
|
|
19
|
+
}
|
|
20
|
+
return roh.map((e) => {
|
|
21
|
+
const d = (e ?? {});
|
|
22
|
+
// Dieselbe Gestalt wie der Empfaenger am Beleg-Item — `TipRecipient` aus
|
|
23
|
+
// src/models/receipt-item.ts. Kein neuer Typ: „wer kann Trinkgeld
|
|
24
|
+
// bekommen" und „wer hat es bekommen" sind dieselbe Sache.
|
|
25
|
+
return { registerUserId: String(d.registerUserId ?? ''), name: String(d.name ?? ''), owner: d.owner === true };
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -18,6 +18,19 @@ export declare const CANCELLATION_REASONS: Readonly<{
|
|
|
18
18
|
}>;
|
|
19
19
|
export type CancellationReason = keyof typeof CANCELLATION_REASONS;
|
|
20
20
|
export declare function isCancellationReason(value: unknown): value is CancellationReason;
|
|
21
|
+
/**
|
|
22
|
+
* Stabile Fehlercodes von `cancelReceipt` — Zwilling von
|
|
23
|
+
* `functions/storno-core.js` STORNO_FEHLERCODES. Das Backend legt sie bei
|
|
24
|
+
* jedem fachlichen Fehler als `code` neben die Meldung; das Paket reicht sie
|
|
25
|
+
* als [KasseneckApiError.code] durch. **Entscheide am Code, nie am Text** —
|
|
26
|
+
* die deutsche Meldung darf sich aendern, der Code nicht.
|
|
27
|
+
*
|
|
28
|
+
* Nur Auth-/Parameterfehler (Sitzung abgelaufen, Pflichtfeld fehlt) kommen
|
|
29
|
+
* ohne Code; dort bleibt `code` undefined.
|
|
30
|
+
*/
|
|
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"];
|
|
32
|
+
export type CancellationErrorCode = (typeof CANCELLATION_ERROR_CODES)[number];
|
|
33
|
+
export declare function isCancellationErrorCode(value: unknown): value is CancellationErrorCode;
|
|
21
34
|
/** Bezug eines Storno-Belegs auf sein Original. */
|
|
22
35
|
export interface CancellationOf {
|
|
23
36
|
receiptId: string;
|
|
@@ -40,6 +53,15 @@ export interface Cancellation {
|
|
|
40
53
|
by: string | null;
|
|
41
54
|
note: string | null;
|
|
42
55
|
items: CancellationItem[];
|
|
56
|
+
/**
|
|
57
|
+
* Rabattgutschein-Ausgleich, den DIESER Storno gewaehrt hat — Cent je
|
|
58
|
+
* Steuertopf des Backends (`amountRateStandard`, `amountRateReduced1`, …).
|
|
59
|
+
* Ein Rabattgutschein ist am Original schon in den Umsatz eingerechnet;
|
|
60
|
+
* jeder Storno nimmt ihn anteilig der stornierten Menge zurueck (bei 3 Stueck
|
|
61
|
+
* a 10 EUR mit 6 EUR Rabatt: 2,00 je Stueck). Fehlt das Feld, hat der Eintrag
|
|
62
|
+
* nichts gewaehrt (Altbestand vor dieser Regel) — der naechste Storno holt nach.
|
|
63
|
+
*/
|
|
64
|
+
promoAdjustmentCents?: Record<string, number>;
|
|
43
65
|
}
|
|
44
66
|
/** Ab wann eine liegengebliebene Reservierung nicht mehr zaehlt (wie im Backend). */
|
|
45
67
|
export declare const CANCELLATION_RESERVATION_MS = 120000;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CANCELLATION_RESERVATION_MS = exports.CANCELLATION_REASONS = void 0;
|
|
3
|
+
exports.CANCELLATION_RESERVATION_MS = exports.CANCELLATION_ERROR_CODES = exports.CANCELLATION_REASONS = void 0;
|
|
4
4
|
exports.isCancellationReason = isCancellationReason;
|
|
5
|
+
exports.isCancellationErrorCode = isCancellationErrorCode;
|
|
5
6
|
exports.remainingQuantities = remainingQuantities;
|
|
6
7
|
/**
|
|
7
8
|
* Storno-Metadaten — Zwilling von `functions/storno-core.js`.
|
|
@@ -23,6 +24,35 @@ exports.CANCELLATION_REASONS = Object.freeze({
|
|
|
23
24
|
function isCancellationReason(value) {
|
|
24
25
|
return typeof value === 'string' && Object.prototype.hasOwnProperty.call(exports.CANCELLATION_REASONS, value);
|
|
25
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Stabile Fehlercodes von `cancelReceipt` — Zwilling von
|
|
29
|
+
* `functions/storno-core.js` STORNO_FEHLERCODES. Das Backend legt sie bei
|
|
30
|
+
* jedem fachlichen Fehler als `code` neben die Meldung; das Paket reicht sie
|
|
31
|
+
* als [KasseneckApiError.code] durch. **Entscheide am Code, nie am Text** —
|
|
32
|
+
* die deutsche Meldung darf sich aendern, der Code nicht.
|
|
33
|
+
*
|
|
34
|
+
* Nur Auth-/Parameterfehler (Sitzung abgelaufen, Pflichtfeld fehlt) kommen
|
|
35
|
+
* ohne Code; dort bleibt `code` undefined.
|
|
36
|
+
*/
|
|
37
|
+
exports.CANCELLATION_ERROR_CODES = [
|
|
38
|
+
'beleg_nicht_gefunden', // Original fehlt oder gehoert nicht zu dieser Kasse
|
|
39
|
+
'belegart_nicht_stornierbar', // Original ist selbst Storno-, Null- oder Startbeleg
|
|
40
|
+
'trainingsbeleg', // Trainingsbelege werden nicht storniert
|
|
41
|
+
'bereits_storniert', // keine Restmenge mehr (auch beim positionslosen Beleg)
|
|
42
|
+
'position_ungueltig', // Index unbekannt oder doppelt
|
|
43
|
+
'menge_ueber_rest', // Menge nicht ganzzahlig >= 1 oder groesser als der Rest
|
|
44
|
+
'grund_unbekannt', // reason fehlt oder nicht im Katalog
|
|
45
|
+
'anmerkung_zu_lang', // note laenger als 200 Zeichen
|
|
46
|
+
'items_ungueltig', // items ist keine Liste
|
|
47
|
+
'kasse_nicht_zugewiesen', // Register-Benutzer darf diese Kasse nicht
|
|
48
|
+
'keine_berechtigung', // Register-Benutzer ohne Storno-Recht
|
|
49
|
+
'nur_eigene_belege', // Recht "eigene", fremder Beleg
|
|
50
|
+
'kasse_unvollstaendig', // api_key/token fehlen am Konto bzw. an der Kasse
|
|
51
|
+
'storno_fehlgeschlagen', // der Storno-Beleg selbst wurde abgelehnt (z. B. Signatur)
|
|
52
|
+
];
|
|
53
|
+
function isCancellationErrorCode(value) {
|
|
54
|
+
return typeof value === 'string' && exports.CANCELLATION_ERROR_CODES.includes(value);
|
|
55
|
+
}
|
|
26
56
|
/** Ab wann eine liegengebliebene Reservierung nicht mehr zaehlt (wie im Backend). */
|
|
27
57
|
exports.CANCELLATION_RESERVATION_MS = 120_000;
|
|
28
58
|
/**
|
|
@@ -44,8 +44,15 @@ function fromHobexReceiptPayload(payload) {
|
|
|
44
44
|
responseCode: payload.responseCode,
|
|
45
45
|
transactionType: payload.transactionType,
|
|
46
46
|
currency: payload.currency,
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
// Euro->Cent ueber die eine gehaertete Stelle im Paket ([euroToCents],
|
|
48
|
+
// money.ts) statt einer eigenen `Math.round(x * 100)` -- die Hobex-Antwort
|
|
49
|
+
// ist eine fremde Antwort und wird hier nur auf transactionId/
|
|
50
|
+
// transactionDate geprueft (siehe payments/hobex.ts, belegAusNutzlast);
|
|
51
|
+
// amount/tip bleiben ungeprueft. Ein nicht-numerischer oder
|
|
52
|
+
// nicht-endlicher Wert ergab bis zu dieser Fassung `NaN` -- lautlos, ohne
|
|
53
|
+
// dass irgendwo geworfen wurde. [euroToCents] liefert dafuer `0`.
|
|
54
|
+
amountCents: (0, money_js_1.euroToCents)(payload.amount),
|
|
55
|
+
tipCents: (0, money_js_1.euroToCents)(payload.tip),
|
|
49
56
|
cvm: String(payload.cvm),
|
|
50
57
|
// Die Cloud-API-Nutzlast traegt keinen eigenen Provider-Schluessel — der
|
|
51
58
|
// Provider ergibt sich aus dem Transportweg (Cloud vs. HPS), nicht aus
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { type ReceiptItem, type ReceiptItemPayload, type ReceiptItemPayloadRead, toReceiptItemPayload, fromReceiptItemPayload, receiptItemTotalCents, receiptItemIsValid, negateReceiptItem, type TipRecipient, isTipItem, isDiscountItem, } from './receipt-item.js';
|
|
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
|
-
export { type CancellationOf, type CancellationItem, type Cancellation, type CancellationReason, CANCELLATION_REASONS, CANCELLATION_RESERVATION_MS, isCancellationReason, remainingQuantities, } from './cancellation.js';
|
|
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
5
|
export { type ReceiptCompany, type ReceiptCompanyPayload, fromReceiptCompanyPayload, receiptCompanyTaxInfo, } from './receipt-company.js';
|
|
6
6
|
export { type Cashregister, type CashregisterOnboarding, type CashregisterPayload, type CashregisterOnboardingPayload, fromCashregisterPayload, } from './cashregister.js';
|
|
7
7
|
export { type ReceiptSummary, type ReceiptSummaryPayload, fromReceiptSummaryPayload, type ZeroKind, ZERO_KINDS, istZeroKind } from './receipt-summary.js';
|
package/dist/cjs/models/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.hobexReceiptNeedsSignature = exports.hobexReceiptToCardPaymentData = exports.fromHobexReceiptPayload = exports.toHobexReceiptPayload = exports.fromStripeUrlSessionPayload = exports.toStripeUrlSessionPayload = exports.reportMonthReadable = exports.reportMonthKey = exports.nextReportMonth = exports.previousReportMonth = exports.reportMonthFromDate = exports.istZeroKind = exports.ZERO_KINDS = exports.fromReceiptSummaryPayload = exports.fromCashregisterPayload = exports.receiptCompanyTaxInfo = exports.fromReceiptCompanyPayload = exports.remainingQuantities = exports.isCancellationReason = exports.CANCELLATION_RESERVATION_MS = exports.CANCELLATION_REASONS = exports.receiptSumCents = exports.receiptSubSumCents = exports.fromReceiptPayload = exports.toReceiptPayload = exports.voucherIsValid = exports.fromVoucherPayload = exports.toVoucherPayload = exports.isDiscountItem = exports.isTipItem = exports.negateReceiptItem = exports.receiptItemIsValid = exports.receiptItemTotalCents = exports.fromReceiptItemPayload = exports.toReceiptItemPayload = void 0;
|
|
3
|
+
exports.hobexReceiptNeedsSignature = exports.hobexReceiptToCardPaymentData = exports.fromHobexReceiptPayload = exports.toHobexReceiptPayload = exports.fromStripeUrlSessionPayload = exports.toStripeUrlSessionPayload = exports.reportMonthReadable = exports.reportMonthKey = exports.nextReportMonth = exports.previousReportMonth = exports.reportMonthFromDate = exports.istZeroKind = exports.ZERO_KINDS = exports.fromReceiptSummaryPayload = exports.fromCashregisterPayload = exports.receiptCompanyTaxInfo = exports.fromReceiptCompanyPayload = exports.remainingQuantities = exports.isCancellationErrorCode = exports.isCancellationReason = exports.CANCELLATION_RESERVATION_MS = exports.CANCELLATION_ERROR_CODES = exports.CANCELLATION_REASONS = exports.receiptSumCents = exports.receiptSubSumCents = exports.fromReceiptPayload = exports.toReceiptPayload = exports.voucherIsValid = exports.fromVoucherPayload = exports.toVoucherPayload = exports.isDiscountItem = exports.isTipItem = exports.negateReceiptItem = exports.receiptItemIsValid = exports.receiptItemTotalCents = exports.fromReceiptItemPayload = exports.toReceiptItemPayload = void 0;
|
|
4
4
|
var receipt_item_js_1 = require("./receipt-item.js");
|
|
5
5
|
Object.defineProperty(exports, "toReceiptItemPayload", { enumerable: true, get: function () { return receipt_item_js_1.toReceiptItemPayload; } });
|
|
6
6
|
Object.defineProperty(exports, "fromReceiptItemPayload", { enumerable: true, get: function () { return receipt_item_js_1.fromReceiptItemPayload; } });
|
|
@@ -20,8 +20,10 @@ Object.defineProperty(exports, "receiptSubSumCents", { enumerable: true, get: fu
|
|
|
20
20
|
Object.defineProperty(exports, "receiptSumCents", { enumerable: true, get: function () { return receipt_js_1.receiptSumCents; } });
|
|
21
21
|
var cancellation_js_1 = require("./cancellation.js");
|
|
22
22
|
Object.defineProperty(exports, "CANCELLATION_REASONS", { enumerable: true, get: function () { return cancellation_js_1.CANCELLATION_REASONS; } });
|
|
23
|
+
Object.defineProperty(exports, "CANCELLATION_ERROR_CODES", { enumerable: true, get: function () { return cancellation_js_1.CANCELLATION_ERROR_CODES; } });
|
|
23
24
|
Object.defineProperty(exports, "CANCELLATION_RESERVATION_MS", { enumerable: true, get: function () { return cancellation_js_1.CANCELLATION_RESERVATION_MS; } });
|
|
24
25
|
Object.defineProperty(exports, "isCancellationReason", { enumerable: true, get: function () { return cancellation_js_1.isCancellationReason; } });
|
|
26
|
+
Object.defineProperty(exports, "isCancellationErrorCode", { enumerable: true, get: function () { return cancellation_js_1.isCancellationErrorCode; } });
|
|
25
27
|
Object.defineProperty(exports, "remainingQuantities", { enumerable: true, get: function () { return cancellation_js_1.remainingQuantities; } });
|
|
26
28
|
var receipt_company_js_1 = require("./receipt-company.js");
|
|
27
29
|
Object.defineProperty(exports, "fromReceiptCompanyPayload", { enumerable: true, get: function () { return receipt_company_js_1.fromReceiptCompanyPayload; } });
|
|
@@ -90,6 +90,9 @@ function leseStorno(eintrag) {
|
|
|
90
90
|
by: eintrag.by ?? null,
|
|
91
91
|
note: eintrag.note ?? null,
|
|
92
92
|
items: (eintrag.items ?? []).map((p) => ({ index: Number(p.index), quantity: Number(p.quantity) })),
|
|
93
|
+
...(eintrag.promoAdjustmentCents && typeof eintrag.promoAdjustmentCents === 'object'
|
|
94
|
+
? { promoAdjustmentCents: Object.fromEntries(Object.entries(eintrag.promoAdjustmentCents).map(([k, v]) => [k, Number(v)])) }
|
|
95
|
+
: {}),
|
|
93
96
|
};
|
|
94
97
|
}
|
|
95
98
|
/**
|
|
@@ -4,6 +4,7 @@ exports.toVoucherPayload = toVoucherPayload;
|
|
|
4
4
|
exports.voucherIsValid = voucherIsValid;
|
|
5
5
|
exports.fromVoucherPayload = fromVoucherPayload;
|
|
6
6
|
const index_js_1 = require("../enums/index.js");
|
|
7
|
+
const money_js_1 = require("../money.js");
|
|
7
8
|
const enum_payload_js_1 = require("./enum-payload.js");
|
|
8
9
|
function toVoucherPayload(voucher) {
|
|
9
10
|
return {
|
|
@@ -35,16 +36,31 @@ function voucherIsValid(voucher) {
|
|
|
35
36
|
if (voucher.type === index_js_1.VoucherType.promo && voucher.valueCents == null) {
|
|
36
37
|
return false;
|
|
37
38
|
}
|
|
38
|
-
|
|
39
|
+
// `!Number.isFinite` VOR den Vergleich, nicht dahinter: `NaN <= 0` und
|
|
40
|
+
// `Infinity <= 0` sind beide `false`, ein Vergleich mit einem
|
|
41
|
+
// nicht-endlichen Wert ist also IMMER falsch und liesse ihn hier
|
|
42
|
+
// durchrutschen. Gemessen (28.08.2026): ein Gutschein mit `valueCents: NaN`
|
|
43
|
+
// (aus einem kaputten `value` in der Nutzlast, siehe [fromVoucherPayload])
|
|
44
|
+
// oder `valueCents: Infinity` galt bis zu dieser Fassung als GUELTIG und
|
|
45
|
+
// waere still in die Belegsummen gewandert. Diese Pruefung greift
|
|
46
|
+
// unabhaengig davon, ob `valueCents` ueber [fromVoucherPayload] oder direkt
|
|
47
|
+
// gesetzt wurde -- die gehaertete Umrechnung dort allein reicht nicht.
|
|
48
|
+
if (voucher.valueCents != null && (!Number.isFinite(voucher.valueCents) || voucher.valueCents <= 0)) {
|
|
39
49
|
return false;
|
|
40
50
|
}
|
|
41
51
|
return true;
|
|
42
52
|
}
|
|
43
53
|
function fromVoucherPayload(payload) {
|
|
54
|
+
// Euro->Cent ueber die eine gehaertete Stelle im Paket ([euroToCents],
|
|
55
|
+
// money.ts) statt einer eigenen `Math.round(payload.value * 100)` --
|
|
56
|
+
// [euroToCents] prueft `Number.isFinite` und liefert fuer einen
|
|
57
|
+
// nicht-numerischen oder nicht-endlichen Wert `0` statt eines lautlosen
|
|
58
|
+
// `NaN`. Siehe auch [voucherIsValid]: `0` faellt dort ueber die
|
|
59
|
+
// "<= 0"-Pruefung, ein `NaN` waere durchgerutscht.
|
|
44
60
|
const valueCents = payload.valueCents != null
|
|
45
61
|
? payload.valueCents
|
|
46
62
|
: payload.value != null
|
|
47
|
-
?
|
|
63
|
+
? (0, money_js_1.euroToCents)(payload.value)
|
|
48
64
|
: undefined;
|
|
49
65
|
return {
|
|
50
66
|
name: payload.name ?? undefined,
|