@kreiseck/kasseneck-api 1.5.0 → 1.5.1

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 (44) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +64 -26
  3. package/dist/cjs/client/aufrufe.d.ts +56 -2
  4. package/dist/cjs/client/aufrufe.js +168 -1
  5. package/dist/cjs/client/errors.d.ts +32 -19
  6. package/dist/cjs/client/errors.js +28 -17
  7. package/dist/cjs/client/index.d.ts +2 -2
  8. package/dist/cjs/client/index.js +2 -1
  9. package/dist/cjs/client/transport.d.ts +27 -1
  10. package/dist/cjs/client/transport.js +25 -27
  11. package/dist/cjs/index.d.ts +1 -1
  12. package/dist/cjs/index.js +3 -2
  13. package/dist/cjs/inventory/schreiben.d.ts +3 -0
  14. package/dist/cjs/inventory/schreiben.js +6 -1
  15. package/dist/cjs/invoice/endpunkte.d.ts +6 -0
  16. package/dist/cjs/invoice/endpunkte.js +13 -2
  17. package/dist/cjs/pos/texte.d.ts +11 -6
  18. package/dist/cjs/pos/texte.js +11 -6
  19. package/dist/cjs/version.d.ts +1 -1
  20. package/dist/cjs/version.js +1 -1
  21. package/dist/esm/client/aufrufe.d.ts +56 -2
  22. package/dist/esm/client/aufrufe.js +166 -0
  23. package/dist/esm/client/errors.d.ts +32 -19
  24. package/dist/esm/client/errors.js +28 -17
  25. package/dist/esm/client/index.d.ts +2 -2
  26. package/dist/esm/client/index.js +1 -1
  27. package/dist/esm/client/transport.d.ts +27 -1
  28. package/dist/esm/client/transport.js +26 -28
  29. package/dist/esm/index.d.ts +1 -1
  30. package/dist/esm/index.js +1 -1
  31. package/dist/esm/inventory/schreiben.d.ts +3 -0
  32. package/dist/esm/inventory/schreiben.js +6 -1
  33. package/dist/esm/invoice/endpunkte.d.ts +6 -0
  34. package/dist/esm/invoice/endpunkte.js +13 -2
  35. package/dist/esm/pos/texte.d.ts +11 -6
  36. package/dist/esm/pos/texte.js +11 -6
  37. package/dist/esm/version.d.ts +1 -1
  38. package/dist/esm/version.js +1 -1
  39. package/fixtures/hobex-hps-codes.json +1 -1
  40. package/fixtures/invoice-api.schema.json +1 -1
  41. package/fixtures/invoice-texts.json +1 -1
  42. package/fixtures/pos-texts.json +1 -1
  43. package/fixtures/surface.json +55 -1
  44. package/package.json +1 -1
@@ -237,6 +237,172 @@ export const POS_CALLS = [
237
237
  'listMyStock',
238
238
  'setMyCashregisterStockLocation',
239
239
  ];
240
+ /**
241
+ * Die Aufrufe **mit Wirkung**, alphabetisch: sie legen etwas an, aendern oder
242
+ * loeschen es, buchen, signieren, bewegen Geld oder senden etwas hinaus
243
+ * (Mail, Druckjob, Probesendung). Scheitert einer, nachdem die Anfrage
244
+ * unterwegs war (Netzfehler, Zeitlimit, HTTP 5xx, unlesbare Erfolgsantwort,
245
+ * HTML mit Kennzeichen), meldet der Transport `outcome: 'unknown'`: der
246
+ * Vorgang kann ausgefuehrt sein.
247
+ *
248
+ * Bis 1.5.0 galt das nur fuer die sechs signierenden und geldbewegenden
249
+ * Aufrufe; ein Wareneingang oder eine Rechnung nach einem Zeitlimit kam als
250
+ * `'rejected'` an, und wer das glaubte und mit NEUEM Idempotenzschluessel
251
+ * neu sendete, buchte doppelt.
252
+ *
253
+ * Geht als `unknownOutcomeCalls` in den Vertrag (`fixtures/surface.json`);
254
+ * der Dart-Zwilling prueft seine Liste dagegen. Jeder Aufruf aus
255
+ * [ALL_CALLS], [PUBLIC_CALLS] und [POS_CALLS] steht entweder hier oder in
256
+ * [CALLS_WITHOUT_EFFECT] (Waechter `test/ausgang-einordnung.test.ts`).
257
+ */
258
+ export const UNKNOWN_OUTCOME_CALLS = [
259
+ 'activateCashregister',
260
+ 'cancelInvoice',
261
+ 'cancelReceipt',
262
+ 'changeStockCondition',
263
+ 'createArticle',
264
+ 'createCreditNote',
265
+ 'createCustomer',
266
+ 'createCustomerCashregister',
267
+ 'createInvoiceItem',
268
+ 'createPartnerCustomer',
269
+ 'createPartnerWebhook',
270
+ 'createPrintJob',
271
+ 'createReceipt',
272
+ 'createReservation',
273
+ 'createWebhook',
274
+ 'deactivateArticle',
275
+ 'deletePartnerWebhook',
276
+ 'deleteWebhook',
277
+ 'extendReservation',
278
+ 'financeWebService',
279
+ 'hobexPayApi',
280
+ 'hobexRefundApi',
281
+ 'issueInvoice',
282
+ 'pairRegisterDevice',
283
+ 'receiveGoods',
284
+ 'recordInvoicePayment',
285
+ 'recordStockLoss',
286
+ 'releaseReservation',
287
+ 'reportCustomerContract',
288
+ 'requestCustomerSignature',
289
+ 'reverseStockMovement',
290
+ 'revokeCustomerMandate',
291
+ 'rotatePartnerWebhookSecret',
292
+ 'rotateWebhookSecret',
293
+ 'sendPartnerCustomerFonLink',
294
+ 'sendPartnerWebhookTest',
295
+ 'sendReceiptEmail',
296
+ 'sendWebhookTest',
297
+ 'setCustomerMandate',
298
+ 'setMyCashregisterStockLocation',
299
+ 'setMyKasseLogo',
300
+ 'setMyKasseSettings',
301
+ 'setMyRegisterDeviceSettings',
302
+ 'stripeCaptureIntent',
303
+ 'transferStock',
304
+ 'unpairRegisterDevice',
305
+ 'updateArticle',
306
+ 'updateCustomer',
307
+ 'updateInvoiceItem',
308
+ 'updatePartnerWebhook',
309
+ 'updateWebhook',
310
+ 'withdrawInvoiceItem',
311
+ ];
312
+ /**
313
+ * Die Aufrufe **ohne Wirkung**, je mit Grund. Bei ihnen bleibt es bei
314
+ * `outcome: 'rejected'`, auch nach Zeitlimit, Netzfehler oder HTTP 5xx; eine
315
+ * Wiederholung bucht nichts doppelt:
316
+ *
317
+ * - `read`: reines Lesen (auch Berichte, Dateien, `generateFullReceiptId`,
318
+ * das nur einen Link-Schluessel ableitet, und `getCustomerCredentials`,
319
+ * dessen Abruf das Backend nur mitschreibt).
320
+ * - `repeatable`: legt etwas an, das ohne die verlorene Antwort niemand
321
+ * erreicht und das von selbst verfaellt, und bucht nichts. Die Sitzung der
322
+ * Kassen-Anmeldung (anmelden, verlaengern, abmelden: eine Wiederholung legt
323
+ * hoechstens eine weitere kurzlebige Sitzung an bzw. verlaengert oder
324
+ * beendet dieselbe noch einmal) und der Stripe-Zahlungslink
325
+ * (`createPaymentLinkStripe`: den Link kennt nur die Antwort, ein nie
326
+ * zugestellter Link wird nie bezahlt; Geld bewegt erst die Zahlung bzw.
327
+ * `stripeCaptureIntent`).
328
+ *
329
+ * Probelaeufe (`previewGoodsReceipt`, `previewInvoice`) teilen den Namen mit
330
+ * dem echten Aufruf und stehen darum nicht hier; die Huellen setzen fuer sie
331
+ * `hasEffect: false` beim Aufruf, das nur zusammen mit `dryRun: true` gilt
332
+ * (siehe `TransportCallOptions`).
333
+ *
334
+ * Paketintern; nicht Teil der Paketoberflaeche.
335
+ */
336
+ export const CALLS_WITHOUT_EFFECT = Object.freeze({
337
+ checkPartnerCustomerEmail: 'read',
338
+ downloadDailyReport: 'read',
339
+ downloadReceipt: 'read',
340
+ downloadReport: 'read',
341
+ createPaymentLinkStripe: 'repeatable',
342
+ endRegisterSession: 'repeatable',
343
+ generateFullReceiptId: 'read',
344
+ getArticle: 'read',
345
+ getCustomer: 'read',
346
+ getCustomerCredentials: 'read',
347
+ getCustomerSignatureStatus: 'read',
348
+ getFirstReceiptDate: 'read',
349
+ getInvoice: 'read',
350
+ getInvoiceItem: 'read',
351
+ getInvoicePdf: 'read',
352
+ getInvoiceSetupStatus: 'read',
353
+ getInvoiceXml: 'read',
354
+ getKasseSettings: 'read',
355
+ getPartnerBilling: 'read',
356
+ getPartnerBillingMonth: 'read',
357
+ getPartnerCustomer: 'read',
358
+ getPartnerInfo: 'read',
359
+ getPrintJob: 'read',
360
+ getReceipt: 'read',
361
+ getReportV2: 'read',
362
+ getReservation: 'read',
363
+ getStock: 'read',
364
+ hobexGetStatus: 'read',
365
+ listArticles: 'read',
366
+ listBrands: 'read',
367
+ listCustomerCashregisters: 'read',
368
+ listInvoiceItems: 'read',
369
+ listInvoices: 'read',
370
+ listLocations: 'read',
371
+ listMyArticleGroups: 'read',
372
+ listMyArticles: 'read',
373
+ listMyCashregisters: 'read',
374
+ listMyPrinters: 'read',
375
+ listMyReceipts: 'read',
376
+ listMyStock: 'read',
377
+ listMyStockLocations: 'read',
378
+ listMyTipRecipients: 'read',
379
+ listPartnerCustomers: 'read',
380
+ listPartnerWebhookDeliveries: 'read',
381
+ listPartnerWebhooks: 'read',
382
+ listRegisterSessionsForDevice: 'read',
383
+ listRegisterUsersForDevice: 'read',
384
+ listReservations: 'read',
385
+ listStock: 'read',
386
+ listStockMovements: 'read',
387
+ listWebhookDeliveries: 'read',
388
+ listWebhooks: 'read',
389
+ lookupArticleByCode: 'read',
390
+ registerPinLogin: 'repeatable',
391
+ registerUserLogin: 'repeatable',
392
+ renewRegisterSession: 'repeatable',
393
+ searchCustomers: 'read',
394
+ });
395
+ const MIT_WIRKUNG = new Set(UNKNOWN_OUTCOME_CALLS);
396
+ /**
397
+ * Hat dieser Aufruf Wirkung, ist sein Ausgang nach Zeitlimit, Netzfehler,
398
+ * HTTP 5xx oder unlesbarer Erfolgsantwort also unklar? `financeWebService`
399
+ * zaehlt mit jedem Vorgang. Ein Name, den dieses Paket nicht kennt (der
400
+ * offene Transport nimmt jeden), ist `false`; wer so einen Aufruf mit Wirkung
401
+ * absetzt, sagt es mit `hasEffect: true`.
402
+ */
403
+ export function isUnknownOutcomeCall(name) {
404
+ return MIT_WIRKUNG.has(name);
405
+ }
240
406
  const OEFFENTLICH = new Set(PUBLIC_CALLS);
241
407
  const KASSENWEG = new Set(POS_CALLS);
242
408
  const NUR_KASSE = new Set(POS_CALLS.filter((name) => !OEFFENTLICH.has(name)));
@@ -25,20 +25,27 @@
25
25
  * **Entscheidend ist `outcome`:** `'rejected'` heisst abgelehnt, nichts
26
26
  * geschehen, Wiederholen hilft nicht. `'unknown'` heisst: der Vorgang kann
27
27
  * ausgefuehrt sein (bei `createReceipt` ein signierter Beleg). Dann **nie
28
- * wiederholen**, sondern das Ergebnis nachlesen (Belegliste, `getReceipt`).
28
+ * blind wiederholen**: Belege, Stornos und Zahlungen nachlesen
29
+ * (Belegliste, `getReceipt`, Terminal-Beleg); ein Aufruf mit
30
+ * `idempotencyKey` (Lager schreiben, Rechnung, Partner-Betrieb mit
31
+ * Schluessel) darf mit **demselben** Schluessel erneut gesendet werden und
32
+ * wirkt genau einmal, nie mit einem neuen. `createInvoiceItem` erkennt die
33
+ * Wiederholung an `source` + `reference` (dieselben Werte erneut senden);
34
+ * Posten aendern oder zurueckziehen und Mandate haben keinen Schluessel:
35
+ * erst nachlesen.
29
36
  * - `KasseneckHttpError` — die Antwort war **keine** verwertbare Huelle:
30
37
  * HTTP 500/404 ohne Huelle, leerer Rumpf oder Text statt JSON. Beim
31
38
  * Bericht-Download gelten dieselben Gruende fuer alles, was kein PDF ist.
32
39
  * `reason` trennt die Faelle maschinenlesbar. Auf einem Aufruf mit
33
- * Wirkung (signierend oder geldbewegend) hat HTTP 5xx
40
+ * Wirkung (`UNKNOWN_OUTCOME_CALLS` in aufrufe.ts) hat HTTP 5xx
34
41
  * `outcome: 'unknown'`, ebenso HTTP 200 mit Kennzeichen, aber leerem oder
35
42
  * unlesbarem Rumpf.
36
43
  * - `KasseneckNetworkError` — die Antwort kam gar nicht: Netz weg, DNS,
37
44
  * abgebrochene Verbindung oder Zeitueberschreitung (`timedOut`). Auch hier
38
45
  * gilt `outcome`: war die Anfrage schon unterwegs und ist der Aufruf einer
39
- * mit Wirkung (signierend: `createReceipt`, `cancelReceipt`,
40
- * `financeWebService`; geldbewegend: `hobexPayApi`, `hobexRefundApi`,
41
- * `stripeCaptureIntent`), ist er `'unknown'`.
46
+ * mit Wirkung (signieren, Geld bewegen, buchen, ausstellen, anlegen,
47
+ * aendern, loeschen, senden; die Liste `UNKNOWN_OUTCOME_CALLS`), ist er
48
+ * `'unknown'`. Lesen und Probelauf bleiben `'rejected'`.
42
49
  * - `KasseneckAuthError` — es kam nicht einmal zur Anfrage, weil die Anmeldung
43
50
  * scheiterte (fehlende Zugangsdaten, oder der Token-/Sitzungsgeber warf).
44
51
  * In der Browser-Kasse mit ihrer 90-Sekunden-Sitzung ist das Alltag, kein
@@ -106,8 +113,10 @@ export declare function causeDigest(ursache: unknown, geheimnisse: readonly stri
106
113
  export declare function fehlerDetails(daten: unknown, geheimnisse: readonly string[]): Record<string, unknown>;
107
114
  /**
108
115
  * Ausgang eines gescheiterten Aufrufs. `'rejected'`: nichts geschehen.
109
- * `'unknown'`: der Vorgang kann ausgefuehrt sein; nie wiederholen, sondern
110
- * das Ergebnis nachlesen.
116
+ * `'unknown'`: der Vorgang kann ausgefuehrt sein; nie blind wiederholen.
117
+ * Belege, Stornos und Zahlungen nachlesen; ein Aufruf mit `idempotencyKey`
118
+ * nur mit **demselben** Schluessel erneut senden (wirkt genau einmal); ohne
119
+ * Schluessel erst nachlesen.
111
120
  */
112
121
  export type ErrorOutcome = 'unknown' | 'rejected';
113
122
  /**
@@ -195,12 +204,12 @@ export declare class KasseneckHttpError extends Error {
195
204
  /** Maschinenlesbarer Grund — trennt den Rewrite-Fall vom 500er ohne Textparsen. */
196
205
  readonly reason: HttpFailureReason;
197
206
  /**
198
- * `'unknown'` auf einem Aufruf mit Wirkung (`createReceipt`,
199
- * `cancelReceipt`, `financeWebService`, `hobexPayApi`, `hobexRefundApi`,
200
- * `stripeCaptureIntent`) bei HTTP 5xx und bei HTTP 200 mit
201
- * Kennzeichen, aber unlesbarem Rumpf (`empty-body`, `not-json` auch bei
202
- * `text/html`, `missing-status`): der Handler kann gelaufen sein, nie wiederholen,
203
- * sondern nachlesen. Sonst `'rejected'` (auch 4xx).
207
+ * `'unknown'` auf einem Aufruf mit Wirkung (`UNKNOWN_OUTCOME_CALLS`:
208
+ * signieren, Geld bewegen, buchen, ausstellen, anlegen, aendern, loeschen,
209
+ * senden) bei HTTP 5xx und bei HTTP 200 mit Kennzeichen, aber unlesbarem
210
+ * Rumpf (`empty-body`, `not-json` auch bei `text/html`, `missing-status`):
211
+ * der Handler kann gelaufen sein, nie blind wiederholen (siehe
212
+ * [ErrorOutcome]). Sonst `'rejected'` (auch 4xx, Lesen und Probelauf).
204
213
  */
205
214
  readonly outcome: ErrorOutcome;
206
215
  constructor(functionName: string, statusCode: number, contentType: string | undefined, reason: HttpFailureReason, outcome?: ErrorOutcome);
@@ -218,9 +227,10 @@ export declare class KasseneckNetworkError extends Error {
218
227
  /** Code der zugrunde liegenden Ursache, sofern unbedenklich (z. B. `ECONNREFUSED`). */
219
228
  readonly causeCode: string | undefined;
220
229
  /**
221
- * `'unknown'`, wenn die Anfrage schon unterwegs war und der Aufruf signiert
222
- * (`createReceipt`, `cancelReceipt`, `financeWebService`): dann nie
223
- * wiederholen, sondern nachlesen. Sonst `'rejected'`.
230
+ * `'unknown'`, wenn die Anfrage schon unterwegs war und der Aufruf Wirkung
231
+ * hat (`UNKNOWN_OUTCOME_CALLS`): dann nie blind wiederholen (siehe
232
+ * [ErrorOutcome]). Sonst `'rejected'`, auch bei Lesen und Probelauf und
233
+ * wenn schon die Anmeldung das Zeitlimit verbrauchte.
224
234
  */
225
235
  readonly outcome: ErrorOutcome;
226
236
  constructor(functionName: string, timedOut: boolean, timeoutMs: number, cause?: CauseDigest, outcome?: ErrorOutcome);
@@ -273,9 +283,12 @@ export declare class KasseneckValidationError extends Error {
273
283
  export type KasseneckError = KasseneckApiError | KasseneckHttpError | KasseneckNetworkError | KasseneckAuthError | KasseneckValidationError;
274
284
  /**
275
285
  * Ist der Ausgang dieses Fehlers unklar (`outcome === 'unknown'`)? Dann den
276
- * Aufruf **nicht wiederholen**, sondern das Ergebnis nachlesen. Gilt fuer
277
- * jede Fehlerart; nur [KasseneckApiError], [KasseneckHttpError] und
278
- * [KasseneckNetworkError] koennen `'unknown'` sein.
286
+ * Aufruf **nicht blind wiederholen**: Belege, Stornos und Zahlungen
287
+ * nachlesen; einen Aufruf mit `idempotencyKey` nur mit **demselben**
288
+ * Schluessel erneut senden (wirkt genau einmal, ein neuer buchte doppelt);
289
+ * ohne Schluessel erst nachlesen. Gilt fuer jede Fehlerart; nur
290
+ * [KasseneckApiError], [KasseneckHttpError] und [KasseneckNetworkError]
291
+ * koennen `'unknown'` sein.
279
292
  */
280
293
  export declare function isOutcomeUnknown(error: unknown): boolean;
281
294
  export declare function isKasseneckApiError(error: unknown): error is KasseneckApiError;
@@ -25,20 +25,27 @@
25
25
  * **Entscheidend ist `outcome`:** `'rejected'` heisst abgelehnt, nichts
26
26
  * geschehen, Wiederholen hilft nicht. `'unknown'` heisst: der Vorgang kann
27
27
  * ausgefuehrt sein (bei `createReceipt` ein signierter Beleg). Dann **nie
28
- * wiederholen**, sondern das Ergebnis nachlesen (Belegliste, `getReceipt`).
28
+ * blind wiederholen**: Belege, Stornos und Zahlungen nachlesen
29
+ * (Belegliste, `getReceipt`, Terminal-Beleg); ein Aufruf mit
30
+ * `idempotencyKey` (Lager schreiben, Rechnung, Partner-Betrieb mit
31
+ * Schluessel) darf mit **demselben** Schluessel erneut gesendet werden und
32
+ * wirkt genau einmal, nie mit einem neuen. `createInvoiceItem` erkennt die
33
+ * Wiederholung an `source` + `reference` (dieselben Werte erneut senden);
34
+ * Posten aendern oder zurueckziehen und Mandate haben keinen Schluessel:
35
+ * erst nachlesen.
29
36
  * - `KasseneckHttpError` — die Antwort war **keine** verwertbare Huelle:
30
37
  * HTTP 500/404 ohne Huelle, leerer Rumpf oder Text statt JSON. Beim
31
38
  * Bericht-Download gelten dieselben Gruende fuer alles, was kein PDF ist.
32
39
  * `reason` trennt die Faelle maschinenlesbar. Auf einem Aufruf mit
33
- * Wirkung (signierend oder geldbewegend) hat HTTP 5xx
40
+ * Wirkung (`UNKNOWN_OUTCOME_CALLS` in aufrufe.ts) hat HTTP 5xx
34
41
  * `outcome: 'unknown'`, ebenso HTTP 200 mit Kennzeichen, aber leerem oder
35
42
  * unlesbarem Rumpf.
36
43
  * - `KasseneckNetworkError` — die Antwort kam gar nicht: Netz weg, DNS,
37
44
  * abgebrochene Verbindung oder Zeitueberschreitung (`timedOut`). Auch hier
38
45
  * gilt `outcome`: war die Anfrage schon unterwegs und ist der Aufruf einer
39
- * mit Wirkung (signierend: `createReceipt`, `cancelReceipt`,
40
- * `financeWebService`; geldbewegend: `hobexPayApi`, `hobexRefundApi`,
41
- * `stripeCaptureIntent`), ist er `'unknown'`.
46
+ * mit Wirkung (signieren, Geld bewegen, buchen, ausstellen, anlegen,
47
+ * aendern, loeschen, senden; die Liste `UNKNOWN_OUTCOME_CALLS`), ist er
48
+ * `'unknown'`. Lesen und Probelauf bleiben `'rejected'`.
42
49
  * - `KasseneckAuthError` — es kam nicht einmal zur Anfrage, weil die Anmeldung
43
50
  * scheiterte (fehlende Zugangsdaten, oder der Token-/Sitzungsgeber warf).
44
51
  * In der Browser-Kasse mit ihrer 90-Sekunden-Sitzung ist das Alltag, kein
@@ -365,12 +372,12 @@ export class KasseneckHttpError extends Error {
365
372
  /** Maschinenlesbarer Grund — trennt den Rewrite-Fall vom 500er ohne Textparsen. */
366
373
  reason;
367
374
  /**
368
- * `'unknown'` auf einem Aufruf mit Wirkung (`createReceipt`,
369
- * `cancelReceipt`, `financeWebService`, `hobexPayApi`, `hobexRefundApi`,
370
- * `stripeCaptureIntent`) bei HTTP 5xx und bei HTTP 200 mit
371
- * Kennzeichen, aber unlesbarem Rumpf (`empty-body`, `not-json` auch bei
372
- * `text/html`, `missing-status`): der Handler kann gelaufen sein, nie wiederholen,
373
- * sondern nachlesen. Sonst `'rejected'` (auch 4xx).
375
+ * `'unknown'` auf einem Aufruf mit Wirkung (`UNKNOWN_OUTCOME_CALLS`:
376
+ * signieren, Geld bewegen, buchen, ausstellen, anlegen, aendern, loeschen,
377
+ * senden) bei HTTP 5xx und bei HTTP 200 mit Kennzeichen, aber unlesbarem
378
+ * Rumpf (`empty-body`, `not-json` auch bei `text/html`, `missing-status`):
379
+ * der Handler kann gelaufen sein, nie blind wiederholen (siehe
380
+ * [ErrorOutcome]). Sonst `'rejected'` (auch 4xx, Lesen und Probelauf).
374
381
  */
375
382
  outcome;
376
383
  constructor(functionName, statusCode, contentType, reason, outcome = 'rejected') {
@@ -396,9 +403,10 @@ export class KasseneckNetworkError extends Error {
396
403
  /** Code der zugrunde liegenden Ursache, sofern unbedenklich (z. B. `ECONNREFUSED`). */
397
404
  causeCode;
398
405
  /**
399
- * `'unknown'`, wenn die Anfrage schon unterwegs war und der Aufruf signiert
400
- * (`createReceipt`, `cancelReceipt`, `financeWebService`): dann nie
401
- * wiederholen, sondern nachlesen. Sonst `'rejected'`.
406
+ * `'unknown'`, wenn die Anfrage schon unterwegs war und der Aufruf Wirkung
407
+ * hat (`UNKNOWN_OUTCOME_CALLS`): dann nie blind wiederholen (siehe
408
+ * [ErrorOutcome]). Sonst `'rejected'`, auch bei Lesen und Probelauf und
409
+ * wenn schon die Anmeldung das Zeitlimit verbrauchte.
402
410
  */
403
411
  outcome;
404
412
  constructor(functionName, timedOut, timeoutMs, cause = {}, outcome = 'rejected') {
@@ -464,9 +472,12 @@ export class KasseneckValidationError extends Error {
464
472
  }
465
473
  /**
466
474
  * Ist der Ausgang dieses Fehlers unklar (`outcome === 'unknown'`)? Dann den
467
- * Aufruf **nicht wiederholen**, sondern das Ergebnis nachlesen. Gilt fuer
468
- * jede Fehlerart; nur [KasseneckApiError], [KasseneckHttpError] und
469
- * [KasseneckNetworkError] koennen `'unknown'` sein.
475
+ * Aufruf **nicht blind wiederholen**: Belege, Stornos und Zahlungen
476
+ * nachlesen; einen Aufruf mit `idempotencyKey` nur mit **demselben**
477
+ * Schluessel erneut senden (wirkt genau einmal, ein neuer buchte doppelt);
478
+ * ohne Schluessel erst nachlesen. Gilt fuer jede Fehlerart; nur
479
+ * [KasseneckApiError], [KasseneckHttpError] und [KasseneckNetworkError]
480
+ * koennen `'unknown'` sein.
470
481
  */
471
482
  export function isOutcomeUnknown(error) {
472
483
  return ((error instanceof KasseneckApiError || error instanceof KasseneckHttpError || error instanceof KasseneckNetworkError)
@@ -1,6 +1,6 @@
1
1
  export { type AuthCredentials, type KasseneckAuth, type ApiKeyAuthOptions, type RegisterUserAuthOptions, apiKeyAuth, registerUserAuth, } from './auth.js';
2
- export { DEFAULT_BASE_URL, POS_BASE_URL, DEFAULT_TIMEOUT_MS, type HttpResponseLike, type HttpRequestInit, type FetchLike, type TransportOptions, type TransportBodyFields, type KasseneckTransport, type KasseneckBinaryTransport, createTransport, createBinaryTransport, } from './transport.js';
3
- export { ALL_CALLS, type ApiCall, PUBLIC_CALLS, POS_CALLS, type PublicCall, type PosCall, } from './aufrufe.js';
2
+ export { DEFAULT_BASE_URL, POS_BASE_URL, DEFAULT_TIMEOUT_MS, type HttpResponseLike, type HttpRequestInit, type FetchLike, type TransportOptions, type TransportBodyFields, type TransportCallOptions, type KasseneckTransport, type KasseneckBinaryTransport, createTransport, createBinaryTransport, } from './transport.js';
3
+ export { ALL_CALLS, type ApiCall, PUBLIC_CALLS, POS_CALLS, UNKNOWN_OUTCOME_CALLS, type PublicCall, type PosCall, } from './aufrufe.js';
4
4
  export { KasseneckApiError, KasseneckAuthError, KasseneckHttpError, KasseneckNetworkError, KasseneckValidationError, type ValidationScope, type KasseneckError, type HttpFailureReason, type CauseDigest, type ErrorOutcome, CLIENT_ERROR_CODES, type ClientErrorCode, isKasseneckApiError, isKasseneckAuthError, isKasseneckHttpError, isKasseneckNetworkError, isKasseneckValidationError, isOutcomeUnknown, } from './errors.js';
5
5
  export { type ReceiptCommonOptions, type SellReceiptOptions, type TipOptions, type TipRecipientShare, type CancelReceiptOptions, type ReceiptWithCompany, sellReceipt, sellReceiptWithCompany, paymentsExpectedCents, cardRefundReference, receiptLayoutFromResult, cancelReceipt, type CancelReceiptResult, zeroReceipt, getReceipt, getReceiptWithCompany, generateFullReceiptId, getFirstReceiptDate, listMyReceipts, type ListMyReceiptsOptions, type ReceiptList, type ReceiptListStats, checkVoucherCombinationError, type SendReceiptEmailOptions, type SendReceiptEmailResult, sendReceiptEmail, } from './receipts.js';
6
6
  export { listMyCashregisters } from './cashregisters.js';
@@ -1,6 +1,6 @@
1
1
  export { apiKeyAuth, registerUserAuth, } from './auth.js';
2
2
  export { DEFAULT_BASE_URL, POS_BASE_URL, DEFAULT_TIMEOUT_MS, createTransport, createBinaryTransport, } from './transport.js';
3
- export { ALL_CALLS, PUBLIC_CALLS, POS_CALLS, } from './aufrufe.js';
3
+ export { ALL_CALLS, PUBLIC_CALLS, POS_CALLS, UNKNOWN_OUTCOME_CALLS, } from './aufrufe.js';
4
4
  export { KasseneckApiError, KasseneckAuthError, KasseneckHttpError, KasseneckNetworkError, KasseneckValidationError, CLIENT_ERROR_CODES, isKasseneckApiError, isKasseneckAuthError, isKasseneckHttpError, isKasseneckNetworkError, isKasseneckValidationError, isOutcomeUnknown, } from './errors.js';
5
5
  export { sellReceipt, sellReceiptWithCompany, paymentsExpectedCents, cardRefundReference, receiptLayoutFromResult, cancelReceipt, zeroReceipt, getReceipt, getReceiptWithCompany, generateFullReceiptId, getFirstReceiptDate, listMyReceipts, checkVoucherCombinationError, sendReceiptEmail, } from './receipts.js';
6
6
  export { listMyCashregisters } from './cashregisters.js';
@@ -33,6 +33,12 @@ import { type KasseneckAuth } from './auth.js';
33
33
  * **Kein Wiederholen fehlgeschlagener Aufrufe.** Ein Beleg ist nicht folgenlos
34
34
  * wiederholbar; ohne entschiedene Idempotenz waere ein automatischer zweiter
35
35
  * Versuch ein zweiter Beleg.
36
+ *
37
+ * **Ausgang je Aufruf.** Ob ein Scheitern nach dem Senden `outcome: 'unknown'`
38
+ * traegt, haengt am Aufruf: mit Wirkung ([UNKNOWN_OUTCOME_CALLS] in
39
+ * aufrufe.ts) ja, Lesen und Probelauf nein. Ein Probelauf traegt denselben
40
+ * Namen wie der echte Aufruf; die Huelle sagt es darum beim Aufruf
41
+ * (`hasEffect: false`, [TransportCallOptions]).
36
42
  */
37
43
  /** Basis-URL der oeffentlichen API (Produktion). */
38
44
  export declare const DEFAULT_BASE_URL = "https://api.kasseneck.at/v3";
@@ -151,7 +157,27 @@ export interface TransportBodyFields {
151
157
  /** Vorgangsart von `financeWebService` (z. B. `status_cashbox`). */
152
158
  method?: string;
153
159
  }
154
- export type KasseneckTransport = <T = unknown>(functionName: string, params?: Record<string, unknown>, extraBodyFields?: TransportBodyFields, secretParams?: readonly string[]) => Promise<T>;
160
+ /**
161
+ * Einstellungen fuer **einen** Aufruf, die nicht mitgesendet werden.
162
+ */
163
+ export interface TransportCallOptions {
164
+ /**
165
+ * Hat dieser Aufruf Wirkung? Entscheidet den Ausgang, wenn er scheitert,
166
+ * nachdem die Anfrage unterwegs war (Netzfehler, Zeitlimit, HTTP 5xx,
167
+ * unlesbare Erfolgsantwort, HTML mit Kennzeichen): `true` ergibt
168
+ * `outcome: 'unknown'`. Ohne Angabe gilt die Liste des Pakets
169
+ * (`UNKNOWN_OUTCOME_CALLS`); ein Name, den sie nicht kennt, gilt dann als
170
+ * ohne Wirkung.
171
+ *
172
+ * `true` fuer einen Aufruf mit Wirkung, den dieses Paket nicht kennt.
173
+ * `false` gilt **nur zusammen mit `params.dryRun === true`** (Probelauf
174
+ * unter dem Namen des echten Aufrufs, schreibt nichts) und ergibt dann
175
+ * `'rejected'`; ohne `dryRun: true` bleibt ein Aufruf aus der Liste
176
+ * `'unknown'`, was immer hier steht.
177
+ */
178
+ hasEffect?: boolean;
179
+ }
180
+ export type KasseneckTransport = <T = unknown>(functionName: string, params?: Record<string, unknown>, extraBodyFields?: TransportBodyFields, secretParams?: readonly string[], options?: TransportCallOptions) => Promise<T>;
155
181
  /**
156
182
  * Ruft eine Backend-Funktion auf, die **Binaerdaten** liefert (die beiden
157
183
  * Bericht-PDFs), und gibt sie als `Uint8Array` zurueck.
@@ -1,5 +1,5 @@
1
1
  import { isRegisterUserAuth } from './auth.js';
2
- import { isPosCall, isPosOnlyCall } from './aufrufe.js';
2
+ import { isPosCall, isPosOnlyCall, isUnknownOutcomeCall } from './aufrufe.js';
3
3
  import { PACKAGE_VERSION } from '../version.js';
4
4
  import { KasseneckApiError, KasseneckAuthError, KasseneckHttpError, KasseneckNetworkError, KasseneckValidationError, causeDigest, fehlerDetails, } from './errors.js';
5
5
  /**
@@ -36,6 +36,12 @@ import { KasseneckApiError, KasseneckAuthError, KasseneckHttpError, KasseneckNet
36
36
  * **Kein Wiederholen fehlgeschlagener Aufrufe.** Ein Beleg ist nicht folgenlos
37
37
  * wiederholbar; ohne entschiedene Idempotenz waere ein automatischer zweiter
38
38
  * Versuch ein zweiter Beleg.
39
+ *
40
+ * **Ausgang je Aufruf.** Ob ein Scheitern nach dem Senden `outcome: 'unknown'`
41
+ * traegt, haengt am Aufruf: mit Wirkung ([UNKNOWN_OUTCOME_CALLS] in
42
+ * aufrufe.ts) ja, Lesen und Probelauf nein. Ein Probelauf traegt denselben
43
+ * Namen wie der echte Aufruf; die Huelle sagt es darum beim Aufruf
44
+ * (`hasEffect: false`, [TransportCallOptions]).
39
45
  */
40
46
  /** Basis-URL der oeffentlichen API (Produktion). */
41
47
  export const DEFAULT_BASE_URL = 'https://api.kasseneck.at/v3';
@@ -56,23 +62,6 @@ const VERSION_WERT = 'v3';
56
62
  const KASSENECK_HOSTS = new Set(['api.kasseneck.at', 'kasse.kasseneck.at']);
57
63
  /** Die 1.x-Linie spricht nur `/v3`: jede Basis endet so (`/v3` oder `/api/v3`). */
58
64
  const V3_ENDE = /\/v3$/;
59
- /**
60
- * Aufrufe mit Wirkung, die nie blind wiederholt werden duerfen: sie signieren
61
- * (`createReceipt`, `cancelReceipt`), loesen bei FinanzOnline etwas aus
62
- * (`financeWebService`) oder bewegen Geld (`hobexPayApi` belastet eine Karte,
63
- * `hobexRefundApi` erstattet, `stripeCaptureIntent` zieht eine vorgemerkte
64
- * Zahlung ein). Scheitert einer, nachdem die Anfrage unterwegs war (Netz,
65
- * Zeitlimit, HTTP 5xx, unlesbare Erfolgsantwort, HTML mit Kennzeichen), ist
66
- * sein Ausgang offen.
67
- */
68
- const UNKNOWN_OUTCOME_CALLS = new Set([
69
- 'createReceipt',
70
- 'cancelReceipt',
71
- 'financeWebService',
72
- 'hobexPayApi',
73
- 'hobexRefundApi',
74
- 'stripeCaptureIntent',
75
- ]);
76
65
  /**
77
66
  * Produkte, die das Backend in `Kasseneck-Client` zaehlt (Positivliste,
78
67
  * Nachtrag §6); alles andere zaehlte dort als `ungueltig`. Das Paket weist
@@ -89,7 +78,7 @@ const CLIENT_MAX = 64;
89
78
  export const DEFAULT_TIMEOUT_MS = 30_000;
90
79
  export function createTransport(options) {
91
80
  const kern = createCore(options);
92
- return (functionName, params, extraBodyFields, secretParams) => kern(functionName, params, extraBodyFields, secretParams, alsText, jsonAuswerten);
81
+ return (functionName, params, extraBodyFields, secretParams, callOptions) => kern(functionName, params, extraBodyFields, secretParams, callOptions, alsText, jsonAuswerten);
93
82
  }
94
83
  /**
95
84
  * Zweiter Einstiegspunkt fuer die Bericht-Downloads. Er liest die Antwort als
@@ -101,7 +90,7 @@ export function createTransport(options) {
101
90
  */
102
91
  export function createBinaryTransport(options) {
103
92
  const kern = createCore(options);
104
- return (functionName, params) => kern(functionName, params, undefined, undefined, alsBytes, pdfAuswerten);
93
+ return (functionName, params) => kern(functionName, params, undefined, undefined, undefined, alsBytes, pdfAuswerten);
105
94
  }
106
95
  /**
107
96
  * Gemeinsamer Kern beider Einstiegspunkte: Anmeldung, Zeitlimit, Anfrage und
@@ -125,12 +114,21 @@ function createCore(options) {
125
114
  * (Berichte, Zahlungen, FinanzOnline), geht an die oeffentliche Basis.
126
115
  */
127
116
  const basisFuer = (functionName) => isPosOnlyCall(functionName) || (kassenweg && isPosCall(functionName)) ? kassenBasis : oeffentlicheBasis;
128
- return async function aufrufen(functionName, params = {}, extraBodyFields, secretParams, lesen, auswerten) {
117
+ return async function aufrufen(functionName, params = {}, extraBodyFields, secretParams, callOptions, lesen, auswerten) {
129
118
  // Die URL nennt die Backend-Funktion, die Fehler nennen den **Vorgang**:
130
119
  // `financeWebService` fuehrt ein Dutzend verschiedener Vorgaenge unter einem
131
120
  // Endpunkt, und ein Fehler, der nur "financeWebService" sagt, verschweigt
132
121
  // dem Aufrufer, welcher davon scheiterte.
133
122
  const fehlerName = extraBodyFields?.method ? `${functionName}/${extraBodyFields.method}` : functionName;
123
+ // Ausgang eines Scheiterns nach dem Senden: offen, wenn der Aufruf Wirkung
124
+ // hat. `hasEffect: true` hebt einen fremden Aufruf auf `unknown`.
125
+ // `hasEffect: false` senkt einen Aufruf mit Wirkung nur, wenn er wirklich
126
+ // ein Probelauf ist (`dryRun === true`, so streng prueft auch das
127
+ // Backend): sonst liefe ein echter Beleg oder eine Buchung nach einem
128
+ // Zeitlimit als `rejected`, und genau das fuehrt zur Doppelbuchung.
129
+ const probelauf = callOptions?.hasEffect === false && params['dryRun'] === true;
130
+ const wirkung = callOptions?.hasEffect === true || (isUnknownOutcomeCall(functionName) && !probelauf);
131
+ const nachDemSenden = wirkung ? 'unknown' : 'rejected';
134
132
  // Das Zeitlimit laeuft ab HIER — es deckt die Anmeldung mit ab. Haengt die
135
133
  // Token-Erneuerung auf flauem Netz, haette der Aufruf sonst weder Ergebnis
136
134
  // noch Fehler, und die Kasse stuende still.
@@ -170,8 +168,9 @@ function createCore(options) {
170
168
  }
171
169
  // Bis hierher kam keine verwertbare Antwort: Netz weg oder Zeitlimit.
172
170
  // Die Anfrage war schon unterwegs: bei einem Aufruf mit Wirkung kann
173
- // der Beleg bzw. die Zahlung entstanden sein (Ausgang unklar, nachlesen).
174
- return new KasseneckNetworkError(fehlerName, abbruch.signal.aborted, zeitlimitMs, causeDigest(ursache, geheimnisse), UNKNOWN_OUTCOME_CALLS.has(functionName) ? 'unknown' : 'rejected');
171
+ // der Vorgang ausgefuehrt sein (Beleg, Zahlung, Buchung, Rechnung;
172
+ // Ausgang unklar).
173
+ return new KasseneckNetworkError(fehlerName, abbruch.signal.aborted, zeitlimitMs, causeDigest(ursache, geheimnisse), nachDemSenden);
175
174
  };
176
175
  const basis = basisFuer(functionName);
177
176
  const url = `${basis}/${encodeURIComponent(functionName)}`;
@@ -225,7 +224,7 @@ function createCore(options) {
225
224
  throw fehler;
226
225
  }
227
226
  // 5xx auf einem Aufruf mit Wirkung: der Handler kann gelaufen sein.
228
- const ausgang = antwort.status >= 500 && UNKNOWN_OUTCOME_CALLS.has(functionName) ? 'unknown' : 'rejected';
227
+ const ausgang = antwort.status >= 500 ? nachDemSenden : 'rejected';
229
228
  throw new KasseneckHttpError(fehlerName, antwort.status, inhaltstyp, 'server-error', ausgang);
230
229
  }
231
230
  // HTTP 200 mit HTML: die Auffangregel der Single-Page-App hat den Aufruf
@@ -233,9 +232,9 @@ function createCore(options) {
233
232
  if (inhaltstyp !== undefined && /^\s*text\/html\b/i.test(inhaltstyp)) {
234
233
  // Mit Kennzeichen hat der `/v3`-Rand den Aufruf gesehen (etwa ein
235
234
  // Proxy, der nur den Inhaltstyp umschreibt). Bei einem Aufruf mit
236
- // Wirkung kann der Beleg bzw. die Zahlung dann entstanden sein: unlesbarer Rumpf,
235
+ // Wirkung kann der Vorgang dann ausgefuehrt sein: unlesbarer Rumpf,
237
236
  // Ausgang unklar, statt `route_missing`.
238
- if (UNKNOWN_OUTCOME_CALLS.has(functionName) && traegtKennzeichen(antwort)) {
237
+ if (nachDemSenden === 'unknown' && traegtKennzeichen(antwort)) {
239
238
  throw new KasseneckHttpError(fehlerName, antwort.status, inhaltstyp, 'not-json', 'unknown');
240
239
  }
241
240
  throw new KasseneckApiError(fehlerName, 'Route fehlt: die Antwort ist eine HTML-Seite statt des Backends', {}, 'route_missing');
@@ -253,8 +252,7 @@ function createCore(options) {
253
252
  // Ab hier kam HTTP 200 mit Kennzeichen: der `/v3`-Rand hat den Aufruf
254
253
  // gesehen. Ist der Rumpf dann unlesbar (gekuerzt von einem Proxy,
255
254
  // abgebrochene Verbindung), kann ein Handler mit Wirkung gelaufen sein.
256
- const unlesbar = UNKNOWN_OUTCOME_CALLS.has(functionName) ? 'unknown' : 'rejected';
257
- return auswerten(koerper, fehlerName, antwort.status, inhaltstyp, geheimnisse, unlesbar);
255
+ return auswerten(koerper, fehlerName, antwort.status, inhaltstyp, geheimnisse, nachDemSenden);
258
256
  }
259
257
  finally {
260
258
  // Ohne Abraeumen haelt der Wecker den Node-Prozess bis zum Zeitlimit wach.
@@ -1,6 +1,6 @@
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
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 RegistrationInfo, type ReceiptPayload, type ReceiptPayloadRead, toReceiptPayload, fromReceiptPayload, receiptSubSumCents, receiptSumCents, type CancellationOf, type CancellationItem, type Cancellation, type CancellationReason, type CancellationErrorCode, type CancellationStatus, type ReturnDisposition, RETURN_DISPOSITIONS, CANCELLATION_REASONS, CANCELLATION_STATUSES, CANCELLATION_ERROR_CODES, CANCELLATION_RESERVATION_MS, isCancellationReason, isReturnDisposition, isCancellationErrorCode, cancellationErrorCode, isCancellationError, cancellationFieldErrors, type CancellationFieldError, type ReceiptPayment, type ReceiptPaymentPayload, type ReceiptPaymentInput, fromReceiptPaymentPayload, toReceiptPaymentPayload, type PaymentErrorCode, PAYMENT_ERROR_CODES, isPaymentErrorCode, paymentErrorCode, isPaymentError, paymentFieldErrors, type PaymentFieldError, type ReceiptEmailErrorCode, type ReceiptEmailVia, RECEIPT_EMAIL_ERROR_CODES, RECEIPT_EMAIL_SEND_ERROR_CODES, type ReceiptEmailSendErrorCode, RECEIPT_EMAIL_VIAS, isReceiptEmailErrorCode, receiptEmailErrorCode, isReceiptEmailError, receiptEmailFieldErrors, type ReceiptEmailFieldError, type ReceiptErrorCode, type ReceiptFieldError, RECEIPT_ERROR_CODES, isReceiptErrorCode, receiptErrorCode, isReceiptError, receiptFieldErrors, 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, isZeroKind, 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
- export { type AuthCredentials, type KasseneckAuth, type ApiKeyAuthOptions, type RegisterUserAuthOptions, apiKeyAuth, registerUserAuth, DEFAULT_BASE_URL, POS_BASE_URL, DEFAULT_TIMEOUT_MS, type HttpResponseLike, type HttpRequestInit, type FetchLike, type TransportOptions, type TransportBodyFields, type KasseneckTransport, type KasseneckBinaryTransport, ALL_CALLS, type ApiCall, PUBLIC_CALLS, POS_CALLS, type PublicCall, type PosCall, createTransport, createBinaryTransport, KasseneckApiError, KasseneckAuthError, KasseneckHttpError, KasseneckNetworkError, KasseneckValidationError, type ValidationScope, type KasseneckError, type HttpFailureReason, type CauseDigest, type ErrorOutcome, CLIENT_ERROR_CODES, type ClientErrorCode, isKasseneckApiError, isKasseneckAuthError, isKasseneckHttpError, isKasseneckNetworkError, isKasseneckValidationError, isOutcomeUnknown, type ReceiptCommonOptions, type SellReceiptOptions, type TipOptions, type TipRecipientShare, type CancelReceiptOptions, type CancelReceiptResult, type ReceiptWithCompany, sellReceipt, sellReceiptWithCompany, paymentsExpectedCents, cardRefundReference, receiptLayoutFromResult, cancelReceipt, zeroReceipt, getReceipt, getReceiptWithCompany, generateFullReceiptId, getFirstReceiptDate, listMyReceipts, type ListMyReceiptsOptions, type ReceiptList, type ReceiptListStats, listMyCashregisters, checkVoucherCombinationError, type SendReceiptEmailOptions, type SendReceiptEmailResult, sendReceiptEmail, downloadDailyReport, downloadMonthlyReport, getReportV2, type ReportV2, type ReportV2Metadata, type ReportV2Options, type CashboxStatus, type SignatureStatus, getCashboxStatus, getSignatureStatus, type KasseneckApi, createKasseneckApi, } from './client/index.js';
3
+ export { type AuthCredentials, type KasseneckAuth, type ApiKeyAuthOptions, type RegisterUserAuthOptions, apiKeyAuth, registerUserAuth, DEFAULT_BASE_URL, POS_BASE_URL, DEFAULT_TIMEOUT_MS, type HttpResponseLike, type HttpRequestInit, type FetchLike, type TransportOptions, type TransportBodyFields, type TransportCallOptions, type KasseneckTransport, type KasseneckBinaryTransport, ALL_CALLS, type ApiCall, PUBLIC_CALLS, POS_CALLS, UNKNOWN_OUTCOME_CALLS, type PublicCall, type PosCall, createTransport, createBinaryTransport, KasseneckApiError, KasseneckAuthError, KasseneckHttpError, KasseneckNetworkError, KasseneckValidationError, type ValidationScope, type KasseneckError, type HttpFailureReason, type CauseDigest, type ErrorOutcome, CLIENT_ERROR_CODES, type ClientErrorCode, isKasseneckApiError, isKasseneckAuthError, isKasseneckHttpError, isKasseneckNetworkError, isKasseneckValidationError, isOutcomeUnknown, type ReceiptCommonOptions, type SellReceiptOptions, type TipOptions, type TipRecipientShare, type CancelReceiptOptions, type CancelReceiptResult, type ReceiptWithCompany, sellReceipt, sellReceiptWithCompany, paymentsExpectedCents, cardRefundReference, receiptLayoutFromResult, cancelReceipt, zeroReceipt, getReceipt, getReceiptWithCompany, generateFullReceiptId, getFirstReceiptDate, listMyReceipts, type ListMyReceiptsOptions, type ReceiptList, type ReceiptListStats, listMyCashregisters, checkVoucherCombinationError, type SendReceiptEmailOptions, type SendReceiptEmailResult, sendReceiptEmail, downloadDailyReport, downloadMonthlyReport, getReportV2, type ReportV2, type ReportV2Metadata, type ReportV2Options, type CashboxStatus, type SignatureStatus, getCashboxStatus, getSignatureStatus, type KasseneckApi, createKasseneckApi, } from './client/index.js';
4
4
  export { type ReceiptDueTip, type ReceiptDueTipRecipient, type ReceiptDueOptions, type ReceiptDueBuckets, type ReceiptDueBreakdown, type ReceiptDueErrorReason, receiptDueCents, receiptDueBreakdown, ReceiptDueError, RECEIPT_DUE_ERROR_REASONS, isReceiptDueError, } from './receipt/due.js';
5
5
  export { parseServerTimeStamp, toViennaWallClock, type ViennaWallClock } from './vienna-time.js';
6
6
  export { type PosBusinessSettings, type PosDeviceSettings, type PosSettings, type ArticleGroup, type PosArticle, POS_BUSINESS_DEFAULTS, POS_DEVICE_DEFAULTS, mergePosSettings, fromArticleGroupPayload, fromPosArticlePayload, listMyArticleGroups, listMyArticles, getPosSettings, setMyPosSettings, setMyRegisterDeviceSettings, distributeDiscount, cancelScopeOf, receiptsScopeOf, stockViewOf, } from './pos/index.js';
package/dist/esm/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { ReceiptType, VatRate, KeckPaymentMethod, CreditCardProvider, VoucherType, VoucherAction, StripeLinkMode, } from './enums/index.js';
2
2
  export { toReceiptItemPayload, fromReceiptItemPayload, receiptItemTotalCents, receiptItemIsValid, negateReceiptItem, isTipItem, toVoucherPayload, fromVoucherPayload, voucherIsValid, toReceiptPayload, fromReceiptPayload, receiptSubSumCents, receiptSumCents, RETURN_DISPOSITIONS, CANCELLATION_REASONS, CANCELLATION_STATUSES, CANCELLATION_ERROR_CODES, CANCELLATION_RESERVATION_MS, isCancellationReason, isReturnDisposition, isCancellationErrorCode, cancellationErrorCode, isCancellationError, cancellationFieldErrors, fromReceiptPaymentPayload, toReceiptPaymentPayload, PAYMENT_ERROR_CODES, isPaymentErrorCode, paymentErrorCode, isPaymentError, paymentFieldErrors, RECEIPT_EMAIL_ERROR_CODES, RECEIPT_EMAIL_SEND_ERROR_CODES, RECEIPT_EMAIL_VIAS, isReceiptEmailErrorCode, receiptEmailErrorCode, isReceiptEmailError, receiptEmailFieldErrors, RECEIPT_ERROR_CODES, isReceiptErrorCode, receiptErrorCode, isReceiptError, receiptFieldErrors, remainingQuantities, fromReceiptCompanyPayload, receiptCompanyTaxInfo, fromCashregisterPayload, fromReceiptSummaryPayload, ZERO_KINDS, isZeroKind, reportMonthFromDate, previousReportMonth, nextReportMonth, reportMonthKey, reportMonthReadable, toStripeUrlSessionPayload, fromStripeUrlSessionPayload, toHobexReceiptPayload, fromHobexReceiptPayload, hobexReceiptToCardPaymentData, hobexReceiptNeedsSignature, } from './models/index.js';
3
- export { apiKeyAuth, registerUserAuth, DEFAULT_BASE_URL, POS_BASE_URL, DEFAULT_TIMEOUT_MS, ALL_CALLS, PUBLIC_CALLS, POS_CALLS, createTransport, createBinaryTransport, KasseneckApiError, KasseneckAuthError, KasseneckHttpError, KasseneckNetworkError, KasseneckValidationError, CLIENT_ERROR_CODES, isKasseneckApiError, isKasseneckAuthError, isKasseneckHttpError, isKasseneckNetworkError, isKasseneckValidationError, isOutcomeUnknown, sellReceipt, sellReceiptWithCompany, paymentsExpectedCents, cardRefundReference, receiptLayoutFromResult, cancelReceipt, zeroReceipt, getReceipt, getReceiptWithCompany, generateFullReceiptId, getFirstReceiptDate, listMyReceipts, listMyCashregisters, checkVoucherCombinationError, sendReceiptEmail, downloadDailyReport, downloadMonthlyReport, getReportV2, getCashboxStatus, getSignatureStatus, createKasseneckApi, } from './client/index.js';
3
+ export { apiKeyAuth, registerUserAuth, DEFAULT_BASE_URL, POS_BASE_URL, DEFAULT_TIMEOUT_MS, ALL_CALLS, PUBLIC_CALLS, POS_CALLS, UNKNOWN_OUTCOME_CALLS, createTransport, createBinaryTransport, KasseneckApiError, KasseneckAuthError, KasseneckHttpError, KasseneckNetworkError, KasseneckValidationError, CLIENT_ERROR_CODES, isKasseneckApiError, isKasseneckAuthError, isKasseneckHttpError, isKasseneckNetworkError, isKasseneckValidationError, isOutcomeUnknown, sellReceipt, sellReceiptWithCompany, paymentsExpectedCents, cardRefundReference, receiptLayoutFromResult, cancelReceipt, zeroReceipt, getReceipt, getReceiptWithCompany, generateFullReceiptId, getFirstReceiptDate, listMyReceipts, listMyCashregisters, checkVoucherCombinationError, sendReceiptEmail, downloadDailyReport, downloadMonthlyReport, getReportV2, getCashboxStatus, getSignatureStatus, createKasseneckApi, } from './client/index.js';
4
4
  export { receiptDueCents, receiptDueBreakdown, ReceiptDueError, RECEIPT_DUE_ERROR_REASONS, isReceiptDueError, } from './receipt/due.js';
5
5
  export { parseServerTimeStamp, toViennaWallClock } from './vienna-time.js';
6
6
  export { POS_BUSINESS_DEFAULTS, POS_DEVICE_DEFAULTS, mergePosSettings, fromArticleGroupPayload, fromPosArticlePayload, listMyArticleGroups, listMyArticles, getPosSettings, setMyPosSettings, setMyRegisterDeviceSettings, distributeDiscount, cancelScopeOf, receiptsScopeOf, stockViewOf, } from './pos/index.js';
@@ -23,6 +23,9 @@
23
23
  * **Wiederholen:** nach einem Zeitlimit oder Netzfehler denselben Aufruf mit
24
24
  * **demselben** `idempotencyKey` noch einmal senden. Er wirkt genau einmal und
25
25
  * liefert die gespeicherte Antwort; ein neuer Schluessel buchte ein zweites Mal.
26
+ * Darum meldet jeder schreibende Aufruf in diesen Faellen (auch HTTP 5xx und
27
+ * unlesbare Antwort) `outcome: 'unknown'`, nie `'rejected'`. Lesen und der
28
+ * Probelauf (`previewGoodsReceipt`) bleiben `'rejected'`.
26
29
  */
27
30
  import type { InternerTransport } from '../client/aufrufe.js';
28
31
  import type { Article, ChangeStockConditionRequest, CreateArticleRequest, CreateReservationRequest, DeactivateArticleRequest, ExtendReservationRequest, GoodsReceiptPreview, GoodsReceiptPreviewRequest, ReceiveGoodsRequest, RecordStockLossRequest, ReleaseReservationRequest, Reservation, ReservationListQuery, ReservationPage, ReverseStockMovementRequest, StockOperation, TransferStockRequest, UpdateArticleRequest } from './typen.js';
@@ -23,6 +23,9 @@
23
23
  * **Wiederholen:** nach einem Zeitlimit oder Netzfehler denselben Aufruf mit
24
24
  * **demselben** `idempotencyKey` noch einmal senden. Er wirkt genau einmal und
25
25
  * liefert die gespeicherte Antwort; ein neuer Schluessel buchte ein zweites Mal.
26
+ * Darum meldet jeder schreibende Aufruf in diesen Faellen (auch HTTP 5xx und
27
+ * unlesbare Antwort) `outcome: 'unknown'`, nie `'rejected'`. Lesen und der
28
+ * Probelauf (`previewGoodsReceipt`) bleiben `'rejected'`.
26
29
  */
27
30
  import { abfrage, anfragefehler, kennung, seitenweise } from './endpunkte.js';
28
31
  import { artikel, liste, naechsterCursor, objekt, reservierung, vorgang, vorschauZeile } from './lesen.js';
@@ -197,7 +200,9 @@ export async function previewGoodsReceipt(transport, request) {
197
200
  delete p.idempotencyKey;
198
201
  schluessel(name, p, { pflicht: false });
199
202
  eingangZahlen(name, p);
200
- const daten = await transport(name, { ...p, dryRun: true });
203
+ // Ein Probelauf schreibt nichts: nach einem Zeitlimit bleibt er `rejected`,
204
+ // obwohl `receiveGoods` sonst Wirkung hat.
205
+ const daten = await transport(name, { ...p, dryRun: true }, undefined, undefined, { hasEffect: false });
201
206
  return { preview: liste(name, daten, 'preview', vorschauZeile) };
202
207
  }
203
208
  const stueckPositionen = (name, p) => positionen(name, p.items, { pflicht: true, menge: 'pflicht' });
@@ -12,6 +12,12 @@
12
12
  * **Nicht automatisch wiederholen.** Wer nach einem Zeitlimit erneut
13
13
  * ausstellt, tut das mit **demselben** `idempotencyKey`: dann kommt die schon
14
14
  * ausgestellte Rechnung zurueck (`replayed: true`) statt einer zweiten.
15
+ * Jeder Aufruf mit Wirkung (ausstellen, stornieren, gutschreiben, Zahlung
16
+ * nachtragen, Kunde anlegen oder aendern) meldet nach Zeitlimit, Netzfehler,
17
+ * HTTP 5xx oder unlesbarer Antwort `outcome: 'unknown'`: er kann gewirkt
18
+ * haben. Mit Schluessel denselben Schluessel erneut senden, ohne Schluessel
19
+ * (`updateCustomer`, `createCustomer` ohne) erst nachlesen. Lesen und der
20
+ * Probelauf (`previewInvoice`) bleiben `'rejected'`.
15
21
  *
16
22
  * Nach dem Senden wird nichts hart gecastet: fehlt ein zugesagtes Feld, wirft
17
23
  * der Aufruf `KasseneckValidationError` mit `scope:'response'`.