@kreiseck/kasseneck-api 0.29.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/CHANGELOG.md +174 -0
  2. package/dist/cjs/client/api.d.ts +3 -3
  3. package/dist/cjs/client/index.d.ts +1 -1
  4. package/dist/cjs/client/receipts.d.ts +32 -3
  5. package/dist/cjs/client/receipts.js +121 -6
  6. package/dist/cjs/enums/keck-payment-method.d.ts +10 -0
  7. package/dist/cjs/enums/keck-payment-method.js +6 -0
  8. package/dist/cjs/index.d.ts +2 -2
  9. package/dist/cjs/index.js +6 -2
  10. package/dist/cjs/kasse/index.d.ts +1 -1
  11. package/dist/cjs/kasse/index.js +5 -1
  12. package/dist/cjs/kasse/settings.d.ts +4 -2
  13. package/dist/cjs/kasse/settings.js +5 -2
  14. package/dist/cjs/kasse/texte.d.ts +444 -34
  15. package/dist/cjs/kasse/texte.js +265 -35
  16. package/dist/cjs/models/cancellation.d.ts +25 -2
  17. package/dist/cjs/models/cancellation.js +20 -1
  18. package/dist/cjs/models/index.d.ts +2 -0
  19. package/dist/cjs/models/index.js +7 -1
  20. package/dist/cjs/models/payment-errors.d.ts +22 -0
  21. package/dist/cjs/models/payment-errors.js +46 -0
  22. package/dist/cjs/models/receipt-payment.d.ts +86 -0
  23. package/dist/cjs/models/receipt-payment.js +40 -0
  24. package/dist/cjs/models/receipt-summary.d.ts +9 -0
  25. package/dist/cjs/models/receipt-summary.js +2 -0
  26. package/dist/cjs/models/receipt.d.ts +9 -0
  27. package/dist/cjs/models/receipt.js +19 -0
  28. package/dist/cjs/payments/hobex-hps/transaction-response.js +28 -28
  29. package/dist/cjs/receipt/layout.js +112 -10
  30. package/dist/esm/client/api.d.ts +3 -3
  31. package/dist/esm/client/index.d.ts +1 -1
  32. package/dist/esm/client/receipts.d.ts +32 -3
  33. package/dist/esm/client/receipts.js +121 -6
  34. package/dist/esm/enums/keck-payment-method.d.ts +10 -0
  35. package/dist/esm/enums/keck-payment-method.js +6 -0
  36. package/dist/esm/index.d.ts +2 -2
  37. package/dist/esm/index.js +1 -1
  38. package/dist/esm/kasse/index.d.ts +1 -1
  39. package/dist/esm/kasse/index.js +1 -1
  40. package/dist/esm/kasse/settings.d.ts +4 -2
  41. package/dist/esm/kasse/settings.js +5 -2
  42. package/dist/esm/kasse/texte.d.ts +444 -34
  43. package/dist/esm/kasse/texte.js +262 -34
  44. package/dist/esm/models/cancellation.d.ts +25 -2
  45. package/dist/esm/models/cancellation.js +20 -1
  46. package/dist/esm/models/index.d.ts +2 -0
  47. package/dist/esm/models/index.js +2 -0
  48. package/dist/esm/models/payment-errors.d.ts +22 -0
  49. package/dist/esm/models/payment-errors.js +42 -0
  50. package/dist/esm/models/receipt-payment.d.ts +86 -0
  51. package/dist/esm/models/receipt-payment.js +36 -0
  52. package/dist/esm/models/receipt-summary.d.ts +9 -0
  53. package/dist/esm/models/receipt-summary.js +2 -0
  54. package/dist/esm/models/receipt.d.ts +9 -0
  55. package/dist/esm/models/receipt.js +19 -0
  56. package/dist/esm/payments/hobex-hps/transaction-response.js +28 -28
  57. package/dist/esm/receipt/layout.js +112 -10
  58. package/fixtures/belege/split-bar-rueckgeld.json +58 -0
  59. package/fixtures/belege/split-eine-karte-trinkgeld.json +75 -0
  60. package/fixtures/belege/split-karte-karte-bar.json +102 -0
  61. package/fixtures/belege/split-langer-betrag.json +74 -0
  62. package/fixtures/belege/split-tischrunde-trinkgeld.json +152 -0
  63. package/fixtures/belege/split-trinkgeld-karte.json +82 -0
  64. package/fixtures/belege/split-zwei-karten-gleicher-anbieter.json +89 -0
  65. package/fixtures/belege/storno-split-teil.json +71 -0
  66. package/fixtures/belege/storno-split-voll.json +100 -0
  67. package/fixtures/erwartet/split-bar-rueckgeld.blatt32.json +194 -0
  68. package/fixtures/erwartet/split-bar-rueckgeld.blatt48.json +182 -0
  69. package/fixtures/erwartet/split-bar-rueckgeld.grid32.txt +28 -0
  70. package/fixtures/erwartet/split-bar-rueckgeld.grid48.txt +26 -0
  71. package/fixtures/erwartet/split-bar-rueckgeld.lines.json +286 -0
  72. package/fixtures/erwartet/split-eine-karte-trinkgeld.blatt32.json +242 -0
  73. package/fixtures/erwartet/split-eine-karte-trinkgeld.blatt48.json +224 -0
  74. package/fixtures/erwartet/split-eine-karte-trinkgeld.grid32.txt +36 -0
  75. package/fixtures/erwartet/split-eine-karte-trinkgeld.grid48.txt +33 -0
  76. package/fixtures/erwartet/split-eine-karte-trinkgeld.lines.json +371 -0
  77. package/fixtures/erwartet/split-karte-karte-bar.blatt32.json +356 -0
  78. package/fixtures/erwartet/split-karte-karte-bar.blatt48.json +338 -0
  79. package/fixtures/erwartet/split-karte-karte-bar.grid32.txt +55 -0
  80. package/fixtures/erwartet/split-karte-karte-bar.grid48.txt +52 -0
  81. package/fixtures/erwartet/split-karte-karte-bar.lines.json +519 -0
  82. package/fixtures/erwartet/split-langer-betrag.blatt32.json +266 -0
  83. package/fixtures/erwartet/split-langer-betrag.blatt48.json +260 -0
  84. package/fixtures/erwartet/split-langer-betrag.grid32.txt +40 -0
  85. package/fixtures/erwartet/split-langer-betrag.grid48.txt +39 -0
  86. package/fixtures/erwartet/split-langer-betrag.lines.json +343 -0
  87. package/fixtures/erwartet/split-tischrunde-trinkgeld.blatt32.json +470 -0
  88. package/fixtures/erwartet/split-tischrunde-trinkgeld.blatt48.json +434 -0
  89. package/fixtures/erwartet/split-tischrunde-trinkgeld.grid32.txt +74 -0
  90. package/fixtures/erwartet/split-tischrunde-trinkgeld.grid48.txt +68 -0
  91. package/fixtures/erwartet/split-tischrunde-trinkgeld.lines.json +740 -0
  92. package/fixtures/erwartet/split-trinkgeld-karte.blatt32.json +272 -0
  93. package/fixtures/erwartet/split-trinkgeld-karte.blatt48.json +254 -0
  94. package/fixtures/erwartet/split-trinkgeld-karte.grid32.txt +41 -0
  95. package/fixtures/erwartet/split-trinkgeld-karte.grid48.txt +38 -0
  96. package/fixtures/erwartet/split-trinkgeld-karte.lines.json +428 -0
  97. package/fixtures/erwartet/split-zwei-karten-gleicher-anbieter.blatt32.json +326 -0
  98. package/fixtures/erwartet/split-zwei-karten-gleicher-anbieter.blatt48.json +296 -0
  99. package/fixtures/erwartet/split-zwei-karten-gleicher-anbieter.grid32.txt +50 -0
  100. package/fixtures/erwartet/split-zwei-karten-gleicher-anbieter.grid48.txt +45 -0
  101. package/fixtures/erwartet/split-zwei-karten-gleicher-anbieter.lines.json +504 -0
  102. package/fixtures/erwartet/storno-split-teil.blatt32.json +230 -0
  103. package/fixtures/erwartet/storno-split-teil.blatt48.json +224 -0
  104. package/fixtures/erwartet/storno-split-teil.grid32.txt +34 -0
  105. package/fixtures/erwartet/storno-split-teil.grid48.txt +33 -0
  106. package/fixtures/erwartet/storno-split-teil.lines.json +304 -0
  107. package/fixtures/erwartet/storno-split-voll.blatt32.json +320 -0
  108. package/fixtures/erwartet/storno-split-voll.blatt48.json +314 -0
  109. package/fixtures/erwartet/storno-split-voll.grid32.txt +49 -0
  110. package/fixtures/erwartet/storno-split-voll.grid48.txt +48 -0
  111. package/fixtures/erwartet/storno-split-voll.lines.json +410 -0
  112. package/fixtures/hobex-hps-codes.json +29 -29
  113. package/fixtures/kasse-settings-standard.json +4 -2
  114. package/fixtures/kasse-texte.json +479 -35
  115. package/fixtures/manifest.json +72 -0
  116. package/fixtures/oberflaeche.json +3 -2
  117. package/fixtures/rechnung-api.schema.json +1 -1
  118. package/fixtures/rechnung-texte.json +1 -1
  119. package/package.json +1 -1
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PAYMENT_ERROR_CODES = void 0;
4
+ exports.isPaymentErrorCode = isPaymentErrorCode;
5
+ /**
6
+ * Mehrere Zahlungen je Beleg — Fehlercode-Katalog, Zwilling von
7
+ * `functions/gemeinsam/zahlungen-core.js` ZAHLUNGS_FEHLERCODES (gleiche
8
+ * Codes, gleiche Reihenfolge).
9
+ *
10
+ * `createReceipt` und `cancelReceipt` legen sie bei jedem Fehler rund um
11
+ * `payments` (und bei den Aufrufer-Vorbedingungen wie `PAYMENTS_CONFLICT`)
12
+ * als `code` neben die Meldung; das Paket reicht sie als
13
+ * [KasseneckApiError.code] durch. **Entscheide am Code, nie am Text** — die
14
+ * deutsche Meldung darf sich aendern, der Code nicht.
15
+ *
16
+ * Schreibweise: auf `/v1`, `/v2` und intern kommen die Codes gross
17
+ * (`PAYMENTS_SUM_MISMATCH`), unter `/v3` schreibt der Rand des Backends sie
18
+ * klein (`payments_sum_mismatch`, functions/gemeinsam/api-vokabular-v3.js:
19
+ * jeder dieser Codes 1:1 in Kleinschreibung, anders als die Storno-Codes).
20
+ * [isPaymentErrorCode] erkennt beide; wer selbst vergleicht, vergleicht
21
+ * `code.toUpperCase()`.
22
+ */
23
+ exports.PAYMENT_ERROR_CODES = Object.freeze([
24
+ 'PAYMENTS_INVALID', // payments ist keine Liste oder hat mehr als 20 Eintraege
25
+ 'PAYMENT_METHOD_INVALID', // Zahlart unbekannt oder mixed
26
+ 'PAYMENT_AMOUNT_INVALID', // amountCents keine Ganzzahl, 0 oder falsches Vorzeichen
27
+ 'PAYMENT_TENDERED_INVALID', // tenderedCents an Nicht-Bar-Zahlung, zu klein oder am Storno
28
+ 'PAYMENT_PROVIDER_INVALID', // Karte ohne/mit unbekanntem provider, providerPaymentId fehlt
29
+ 'PAYMENT_PROVIDER_NOT_ALLOWED', // Anbieterfelder an einer Zahlung, die weder Karte noch online ist
30
+ 'PAYMENTS_SUM_MISMATCH', // Summe != Zahlbetrag (Antwort nennt data.expectedCents)
31
+ 'PAYMENTS_DUE_NEGATIVE', // Zahlbetrag < 0 (Wertgutschein groesser als der Beleg)
32
+ 'PAYMENTS_NOT_ALLOWED', // Null-/Startbeleg mit Zahlungen, alter Storno-Weg
33
+ 'PAYMENTS_CONFLICT', // payments zusammen mit paymentMethod oder Kartenfeldern
34
+ 'PAYMENTS_REQUIRED', // /v3 ohne payments
35
+ 'PAYMENT_METHOD_NOT_SUPPORTED', // paymentMethod/Kartenfelder unter /v3
36
+ 'TIP_PAYMENT_METHOD_INVALID', // Trinkgeld-Zahlart kommt in payments nicht vor
37
+ 'TIP_PAYMENT_METHOD_REQUIRED', // mehrere Zahlarten, tip.paymentMethod fehlt
38
+ 'TIP_EXCEEDS_PAYMENT', // Trinkgeld uebersteigt die Zahlungen seiner Zahlart
39
+ 'PAYMENT_REFUND_NOT_ALLOWED', // refundOf ausserhalb eines Stornos oder kein String
40
+ 'PAYMENT_TIP_INVALID', // tipCents keine Ganzzahl, <= 0, > amountCents oder nicht am Verkauf
41
+ 'TIP_CONFLICT', // tip und payments[].tipCents zugleich
42
+ ]);
43
+ /** Erkennt einen Code aus [PAYMENT_ERROR_CODES] — gross (`/v1`) wie klein (`/v3`). */
44
+ function isPaymentErrorCode(value) {
45
+ return typeof value === 'string' && exports.PAYMENT_ERROR_CODES.includes(value.toUpperCase());
46
+ }
@@ -0,0 +1,86 @@
1
+ import { KeckPaymentMethod, type KeckPaymentMethodKey, CreditCardProvider } from '../enums/index.js';
2
+ /**
3
+ * Eine Zahlung am Beleg — Zwilling der Eintraege in `payments`, wie
4
+ * `functions/gemeinsam/zahlungen-core.js` (`pruefeZahlungen`) sie normalisiert
5
+ * und ablegt.
6
+ *
7
+ * Ein Beleg kann ueber mehrere Zahlungen bezahlt sein (zwei Karten, Rest bar).
8
+ * Dann steht die Liste unter `payments`, und das Einzelfeld `paymentMethod`
9
+ * ist `mixed`, sobald verschiedene Zahlarten vorkommen (zwei Karten ergeben
10
+ * `creditCard`). Altbelege haben keine Liste; dort gilt weiter
11
+ * `paymentMethod` samt Kartenfeldern.
12
+ *
13
+ * Betraege in ganzen Cent: am Verkauf positiv, am Storno negativ (Rueckzahlung).
14
+ * `method`/`provider` sind beim Lesen wie ueberall entweder der bekannte
15
+ * Enum-Eintrag oder der rohe Schluessel (siehe `enum-payload.ts`).
16
+ */
17
+ export interface ReceiptPayment {
18
+ /** Vom Server vergeben (`p1`, `p2`, …); Bezugspunkt fuer `refundOf`. */
19
+ id?: string;
20
+ method: KeckPaymentMethod | string;
21
+ amountCents: number;
22
+ /** Nur bei Barzahlung: gegebener Betrag. */
23
+ tenderedCents?: number;
24
+ /** Nur neben `tenderedCents`: Rueckgeld (vom Server gerechnet). */
25
+ changeCents?: number;
26
+ /** Kartenanbieter bzw. Terminal. */
27
+ provider?: CreditCardProvider | string;
28
+ /** Kennung der Zahlung am Terminal/Anbieter. */
29
+ providerPaymentId?: string;
30
+ /** Terminaldaten fuer den Kartenblock (frueher `cardPaymentData`). */
31
+ providerData?: Record<string, unknown>;
32
+ /** Nur am Storno: `id` der Originalzahlung, die erstattet wird. */
33
+ refundOf?: string;
34
+ /**
35
+ * Trinkgeld, das mit dieser Zahlung gegeben wurde, in ganzen Cent — TEIL
36
+ * von `amountCents` (das Terminal bucht Betrag + Trinkgeld zusammen). Nur
37
+ * an Verkaufs-/Trainingsbelegen.
38
+ */
39
+ tipCents?: number;
40
+ }
41
+ /** Nutzlast-Form einer Zahlung (Backend-Dokument bzw. Antwort). */
42
+ export interface ReceiptPaymentPayload {
43
+ id?: string;
44
+ method: string;
45
+ amountCents: number;
46
+ tenderedCents?: number;
47
+ changeCents?: number;
48
+ provider?: string;
49
+ providerPaymentId?: string;
50
+ providerData?: Record<string, unknown>;
51
+ refundOf?: string;
52
+ tipCents?: number;
53
+ }
54
+ /**
55
+ * Eine Zahlung, wie der Aufrufer sie an `createReceipt`/`sellReceipt`/
56
+ * `cancelReceipt` schickt. `id` und `changeCents` vergibt der Server.
57
+ *
58
+ * - `method`: jede Zahlungsart ausser `mixed`.
59
+ * - `amountCents`: ganze Cent, am Verkauf > 0, am Storno < 0.
60
+ * - `tenderedCents`: nur bei Barzahlung am Verkauf; jede Barzahlung darf ihren
61
+ * eigenen gegebenen Betrag tragen (getrennt zahlen: Rueckgeld je Gast).
62
+ * - `provider`/`providerPaymentId`/`providerData`: bei Karten Pflicht
63
+ * (`providerPaymentId` ausser bei `custom`), bei `online` optional, sonst
64
+ * nicht erlaubt; am Storno beschreiben sie die Erstattung und sind optional.
65
+ * - `refundOf`: nur am Storno.
66
+ * - `tipCents`: Trinkgeld dieser Zahlung, ganze Cent > 0, Teil von
67
+ * `amountCents`; nur am Verkauf, nie neben `tip` (den Rest prueft der Server).
68
+ */
69
+ export interface ReceiptPaymentInput {
70
+ method: KeckPaymentMethod | KeckPaymentMethodKey;
71
+ amountCents: number;
72
+ tenderedCents?: number;
73
+ provider?: CreditCardProvider;
74
+ providerPaymentId?: string;
75
+ providerData?: Record<string, unknown>;
76
+ refundOf?: string;
77
+ tipCents?: number;
78
+ }
79
+ /** Lesepfad: nur vorhandene Felder uebernehmen, nichts ergaenzen. */
80
+ export declare function fromReceiptPaymentPayload(payload: ReceiptPaymentPayload): ReceiptPayment;
81
+ /**
82
+ * Schreibpfad: Zahlungen zurueck in die Nutzlast — streng wie
83
+ * `toReceiptPayload`: ein roher, unbekannter Schluessel bei `method` oder
84
+ * `provider` wirft.
85
+ */
86
+ export declare function toReceiptPaymentPayload(payment: ReceiptPayment): ReceiptPaymentPayload;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fromReceiptPaymentPayload = fromReceiptPaymentPayload;
4
+ exports.toReceiptPaymentPayload = toReceiptPaymentPayload;
5
+ const index_js_1 = require("../enums/index.js");
6
+ const enum_payload_js_1 = require("./enum-payload.js");
7
+ /** Lesepfad: nur vorhandene Felder uebernehmen, nichts ergaenzen. */
8
+ function fromReceiptPaymentPayload(payload) {
9
+ return {
10
+ ...(typeof payload.id === 'string' ? { id: payload.id } : {}),
11
+ method: (0, enum_payload_js_1.readEnumKey)(index_js_1.KeckPaymentMethod, payload.method),
12
+ amountCents: payload.amountCents,
13
+ ...(typeof payload.tenderedCents === 'number' ? { tenderedCents: payload.tenderedCents } : {}),
14
+ ...(typeof payload.changeCents === 'number' ? { changeCents: payload.changeCents } : {}),
15
+ ...(typeof payload.provider === 'string' ? { provider: (0, enum_payload_js_1.readEnumKey)(index_js_1.CreditCardProvider, payload.provider) } : {}),
16
+ ...(typeof payload.providerPaymentId === 'string' ? { providerPaymentId: payload.providerPaymentId } : {}),
17
+ ...(payload.providerData != null && typeof payload.providerData === 'object' ? { providerData: payload.providerData } : {}),
18
+ ...(typeof payload.refundOf === 'string' ? { refundOf: payload.refundOf } : {}),
19
+ ...(typeof payload.tipCents === 'number' ? { tipCents: payload.tipCents } : {}),
20
+ };
21
+ }
22
+ /**
23
+ * Schreibpfad: Zahlungen zurueck in die Nutzlast — streng wie
24
+ * `toReceiptPayload`: ein roher, unbekannter Schluessel bei `method` oder
25
+ * `provider` wirft.
26
+ */
27
+ function toReceiptPaymentPayload(payment) {
28
+ return {
29
+ ...(payment.id !== undefined ? { id: payment.id } : {}),
30
+ method: typeof payment.method === 'object' ? payment.method.value : (0, enum_payload_js_1.requireEnumKey)(index_js_1.KeckPaymentMethod, payment.method, 'Zahlungsart').value,
31
+ amountCents: payment.amountCents,
32
+ ...(payment.tenderedCents !== undefined ? { tenderedCents: payment.tenderedCents } : {}),
33
+ ...(payment.changeCents !== undefined ? { changeCents: payment.changeCents } : {}),
34
+ ...(payment.provider !== undefined ? { provider: (0, enum_payload_js_1.requireEnumKey)(index_js_1.CreditCardProvider, payment.provider, 'Kartenanbieter') } : {}),
35
+ ...(payment.providerPaymentId !== undefined ? { providerPaymentId: payment.providerPaymentId } : {}),
36
+ ...(payment.providerData !== undefined ? { providerData: payment.providerData } : {}),
37
+ ...(payment.refundOf !== undefined ? { refundOf: payment.refundOf } : {}),
38
+ ...(payment.tipCents !== undefined ? { tipCents: payment.tipCents } : {}),
39
+ };
40
+ }
@@ -1,4 +1,5 @@
1
1
  import { KeckPaymentMethod, ReceiptType } from '../enums/index.js';
2
+ import { type ReceiptPayment, type ReceiptPaymentPayload } from './receipt-payment.js';
2
3
  /**
3
4
  * Belegzeile einer Liste — die Form, die `listMyReceipts` liefert
4
5
  * (`projectReceiptForCustomer` in functions/index.js).
@@ -63,6 +64,13 @@ export interface ReceiptSummary {
63
64
  stornoStand: 'offen' | 'teil' | 'voll';
64
65
  /** Nur am Nullbeleg, nur fuer Kassen-Benutzer: Anlass (monthly, annual, annual_replacement, outage_end, final, manual). */
65
66
  zeroKind?: ZeroKind;
67
+ /**
68
+ * Zahlungsliste, nur bei Belegen, die eine tragen. Die Liste liefert nur
69
+ * die oeffentlichen Felder (id, method, amountCents, provider,
70
+ * tenderedCents, changeCents, refundOf, tipCents) — Anbieter-Interna
71
+ * (`providerPaymentId`, `providerData`) bleiben im Backend.
72
+ */
73
+ payments?: ReceiptPayment[];
66
74
  }
67
75
  export interface ReceiptSummaryPayload {
68
76
  receiptId?: string | null;
@@ -90,5 +98,6 @@ export interface ReceiptSummaryPayload {
90
98
  cancellationReason?: string | null;
91
99
  stornoStand?: string | null;
92
100
  zeroKind?: string | null;
101
+ payments?: ReceiptPaymentPayload[] | null;
93
102
  }
94
103
  export declare function fromReceiptSummaryPayload(payload: ReceiptSummaryPayload): ReceiptSummary;
@@ -6,6 +6,7 @@ exports.fromReceiptSummaryPayload = fromReceiptSummaryPayload;
6
6
  const index_js_1 = require("../enums/index.js");
7
7
  const money_js_1 = require("../money.js");
8
8
  const enum_payload_js_1 = require("./enum-payload.js");
9
+ const receipt_payment_js_1 = require("./receipt-payment.js");
9
10
  /**
10
11
  * Belegzeile einer Liste — die Form, die `listMyReceipts` liefert
11
12
  * (`projectReceiptForCustomer` in functions/index.js).
@@ -53,5 +54,6 @@ function fromReceiptSummaryPayload(payload) {
53
54
  ...(payload.cancellationReason ? { cancellationReason: payload.cancellationReason } : {}),
54
55
  stornoStand: payload.stornoStand === 'teil' || payload.stornoStand === 'voll' ? payload.stornoStand : 'offen',
55
56
  ...(istZeroKind(payload.zeroKind) ? { zeroKind: payload.zeroKind } : {}),
57
+ ...(Array.isArray(payload.payments) ? { payments: payload.payments.map(receipt_payment_js_1.fromReceiptPaymentPayload) } : {}),
56
58
  };
57
59
  }
@@ -3,6 +3,7 @@ import { type ReceiptItem, type ReceiptItemPayload, type ReceiptItemPayloadRead
3
3
  import { type Voucher, type VoucherPayload } from './voucher.js';
4
4
  import type { Cancellation, CancellationOf, CancellationReason } from './cancellation.js';
5
5
  import { type ZeroKind } from './receipt-summary.js';
6
+ import { type ReceiptPayment, type ReceiptPaymentPayload } from './receipt-payment.js';
6
7
  /**
7
8
  * Beleg — Zwilling der Beleg-Nutzlast von `KasseneckReceipt` in
8
9
  * kasseneck_api/lib/models/kasseneck_receipt.dart (nur der signatur-/
@@ -54,6 +55,12 @@ export interface Receipt {
54
55
  cancellations?: Cancellation[];
55
56
  /** Nur an Nullbelegen: Anlass (monthly, annual, annual_replacement, outage_end, final, manual). */
56
57
  zeroKind?: ZeroKind;
58
+ /**
59
+ * Zahlungsliste (mehrere Zahlungen je Beleg), nur vorhanden, wenn der Beleg
60
+ * sie traegt. Altbelege haben keine; dort gelten `paymentMethod` und die
61
+ * Kartenfelder. Siehe [ReceiptPayment].
62
+ */
63
+ payments?: ReceiptPayment[];
57
64
  }
58
65
  export interface ReceiptPayload {
59
66
  qr: string;
@@ -78,6 +85,8 @@ export interface ReceiptPayload {
78
85
  customProjectId: string | null;
79
86
  /** Nur bei Belegen mit Trinkgeld (siehe [Receipt.tipCents]). */
80
87
  tipCents?: number | null;
88
+ /** Nur bei Belegen mit Zahlungsliste (siehe [Receipt.payments]). */
89
+ payments?: ReceiptPaymentPayload[] | null;
81
90
  }
82
91
  /**
83
92
  * Nutzlast-Form, die dieses Paket **liest**. Unterscheidet sich von
@@ -9,6 +9,7 @@ const enum_payload_js_1 = require("./enum-payload.js");
9
9
  const receipt_item_js_1 = require("./receipt-item.js");
10
10
  const voucher_js_1 = require("./voucher.js");
11
11
  const receipt_summary_js_1 = require("./receipt-summary.js");
12
+ const receipt_payment_js_1 = require("./receipt-payment.js");
12
13
  /**
13
14
  * Schreibt die Nutzlast in der **neuen** Form — sie **normalisiert, statt zu
14
15
  * spiegeln**: ein Beleg, der in der v1-Positionsform gelesen wurde, geht hier
@@ -49,6 +50,7 @@ function toReceiptPayload(receipt) {
49
50
  signatureSuccess: receipt.signatureSuccess ?? null,
50
51
  customProjectId: receipt.customProjectId ?? null,
51
52
  ...(receipt.tipCents != null ? { tipCents: receipt.tipCents } : {}),
53
+ ...(receipt.payments != null ? { payments: receipt.payments.map(receipt_payment_js_1.toReceiptPaymentPayload) } : {}),
52
54
  };
53
55
  }
54
56
  // Nullbelege haben keine Positionen -> items kann fehlen/null sein (siehe Dart-Vorbild).
@@ -84,6 +86,7 @@ function fromReceiptPayload(payload) {
84
86
  ...(payload.cancellationReason ? { cancellationReason: payload.cancellationReason } : {}),
85
87
  ...((0, receipt_summary_js_1.istZeroKind)(payload.zeroKind) ? { zeroKind: payload.zeroKind } : {}),
86
88
  ...(payload.cancellations ? { cancellations: payload.cancellations.map(leseStorno) } : {}),
89
+ ...(Array.isArray(payload.payments) ? { payments: payload.payments.map(receipt_payment_js_1.fromReceiptPaymentPayload) } : {}),
87
90
  };
88
91
  }
89
92
  function leseStorno(eintrag) {
@@ -97,8 +100,24 @@ function leseStorno(eintrag) {
97
100
  ...(eintrag.promoAdjustmentCents && typeof eintrag.promoAdjustmentCents === 'object'
98
101
  ? { promoAdjustmentCents: Object.fromEntries(Object.entries(eintrag.promoAdjustmentCents).map(([k, v]) => [k, Number(v)])) }
99
102
  : {}),
103
+ ...(eintrag.refundedByPayment && typeof eintrag.refundedByPayment === 'object' && !Array.isArray(eintrag.refundedByPayment)
104
+ ? { refundedByPayment: gueltigeRueckzahlungen(eintrag.refundedByPayment) }
105
+ : {}),
100
106
  };
101
107
  }
108
+ // Nur ganzzahlige, nicht-negative Cent-Betraege je Zahlungs-ID; ein Eintrag,
109
+ // der das nicht erfuellt (negativ, Kommazahl, kein Zahlenwert), faellt weg --
110
+ // die uebrigen bleiben. Zwilling der Backend-Erzeugung (storno-core.js
111
+ // pruefeRueckzahlungen), die selbst nur so etwas ablegt.
112
+ function gueltigeRueckzahlungen(rueckzahlungen) {
113
+ const raus = {};
114
+ for (const [id, wert] of Object.entries(rueckzahlungen)) {
115
+ const cents = Number(wert);
116
+ if (Number.isInteger(cents) && cents >= 0)
117
+ raus[id] = cents;
118
+ }
119
+ return raus;
120
+ }
102
121
  /**
103
122
  * Zwischensumme in **Cent** — Positionen plus verkaufte Wertgutscheine minus
104
123
  * eingeloeste Promotionsgutscheine. Wertgutschein-Einloesungen wirken erst auf
@@ -59,40 +59,40 @@ const tecs_codes_js_1 = require("./tecs-codes.js");
59
59
  /** Der Satz fuer den Bediener je Grund, deutsch. */
60
60
  exports.HPS_REASON_HINTS = {
61
61
  approved: 'Vom Terminal genehmigt.',
62
- approvedWithCondition: 'Das Terminal meldet eine Genehmigung mit Vorbehalt (etwa nur über einen Teilbetrag). Ob und in welcher Höhe belastet wurde, bitte am Terminalbeleg prüfen — nicht erneut kassieren, bevor es geklärt ist.',
62
+ approvedWithCondition: 'Das Terminal meldet eine Genehmigung mit Vorbehalt (etwa nur über einen Teilbetrag). Ob und in welcher Höhe belastet wurde, bitte am Terminalbeleg prüfen – nicht erneut kassieren, bevor es geklärt ist.',
63
63
  aborted: 'Der Vorgang wurde abgebrochen. Es wurde kein Geld bewegt.',
64
- noCard: 'Es wurde keine Karte vorgehalten. Es wurde kein Geld bewegt — bitte erneut versuchen.',
65
- cardReadFailed: 'Die Karte konnte nicht gelesen werden. Es wurde kein Geld bewegt — bitte erneut versuchen, notfalls die Karte stecken statt auflegen.',
66
- cardDeclined: 'Die Karte wurde vom Terminal abgelehnt. Es wurde kein Geld bewegt — bitte eine andere Karte oder Zahlungsart verwenden.',
67
- issuerDeclined: 'Die Zahlung wurde von der Bank abgelehnt. Es wurde kein Geld bewegt — bitte eine andere Karte oder Zahlungsart verwenden.',
68
- cardBlocked: 'Die Karte ist gesperrt. Es wurde kein Geld bewegt — bitte eine andere Karte oder Zahlungsart verwenden.',
69
- cardExpired: 'Die Karte ist abgelaufen. Es wurde kein Geld bewegt — bitte eine andere Karte oder Zahlungsart verwenden.',
70
- insufficientFunds: 'Das Konto ist nicht gedeckt oder das Kartenlimit ist erreicht. Es wurde kein Geld bewegt — bitte eine andere Karte oder Zahlungsart verwenden.',
71
- wrongPin: 'Die PIN war falsch. Es wurde kein Geld bewegt — bitte erneut versuchen.',
72
- pinTriesExceeded: 'Die PIN wurde zu oft falsch eingegeben. Es wurde kein Geld bewegt — bitte eine andere Karte oder Zahlungsart verwenden.',
73
- pinRequired: 'Die Bank verlangt die PIN. Es wurde kein Geld bewegt — bitte erneut versuchen, die Karte stecken und die PIN eingeben.',
64
+ noCard: 'Es wurde keine Karte vorgehalten. Es wurde kein Geld bewegt – bitte erneut versuchen.',
65
+ cardReadFailed: 'Die Karte konnte nicht gelesen werden. Es wurde kein Geld bewegt – bitte erneut versuchen, notfalls die Karte stecken statt auflegen.',
66
+ cardDeclined: 'Die Karte wurde vom Terminal abgelehnt. Es wurde kein Geld bewegt – bitte eine andere Karte oder Zahlungsart verwenden.',
67
+ issuerDeclined: 'Die Zahlung wurde von der Bank abgelehnt. Es wurde kein Geld bewegt – bitte eine andere Karte oder Zahlungsart verwenden.',
68
+ cardBlocked: 'Die Karte ist gesperrt. Es wurde kein Geld bewegt – bitte eine andere Karte oder Zahlungsart verwenden.',
69
+ cardExpired: 'Die Karte ist abgelaufen. Es wurde kein Geld bewegt – bitte eine andere Karte oder Zahlungsart verwenden.',
70
+ insufficientFunds: 'Das Konto ist nicht gedeckt oder das Kartenlimit ist erreicht. Es wurde kein Geld bewegt – bitte eine andere Karte oder Zahlungsart verwenden.',
71
+ wrongPin: 'Die PIN war falsch. Es wurde kein Geld bewegt – bitte erneut versuchen.',
72
+ pinTriesExceeded: 'Die PIN wurde zu oft falsch eingegeben. Es wurde kein Geld bewegt – bitte eine andere Karte oder Zahlungsart verwenden.',
73
+ pinRequired: 'Die Bank verlangt die PIN. Es wurde kein Geld bewegt – bitte erneut versuchen, die Karte stecken und die PIN eingeben.',
74
74
  amountInvalid: 'Das Terminal nimmt diesen Betrag nicht an. Es wurde kein Geld bewegt.',
75
- tipNotSelected: 'Das Trinkgeld wurde nicht rechtzeitig gewählt. Es wurde kein Geld bewegt — bitte erneut versuchen.',
76
- terminalBusy: 'Das Terminal ist noch mit einem anderen Vorgang beschäftigt. Es wurde kein Geld bewegt — kurz warten und erneut versuchen.',
77
- terminalBlocked: 'Das Terminal ist gesperrt. Es wurde kein Geld bewegt — bitte hobex kontaktieren.',
78
- terminalSetup: 'Das Terminal ist nicht richtig eingerichtet. Es wurde kein Geld bewegt — bitte die Terminal-ID in den Einstellungen prüfen, sonst hobex kontaktieren.',
79
- acquirerSetup: 'hobex nimmt dieses Terminal oder diesen Händler so nicht an. Es wurde kein Geld bewegt — bitte hobex kontaktieren.',
80
- terminalFault: 'Das Terminal meldet eine Störung. Es wurde kein Geld bewegt — bitte das Terminal neu starten und erneut versuchen.',
81
- requestRejected: 'Das Terminal hat die Anfrage abgewiesen. Es wurde kein Geld bewegt — tritt das wieder auf, bitte den Support kontaktieren.',
82
- hostRejected: 'hobex hat die Zahlung abgewiesen. Es wurde kein Geld bewegt — bitte erneut versuchen; tritt das wieder auf, hobex kontaktieren.',
83
- hostUnavailable: 'Die Bank oder hobex ist gerade nicht erreichbar. Es wurde kein Geld bewegt — bitte später erneut versuchen oder eine andere Zahlungsart verwenden.',
75
+ tipNotSelected: 'Das Trinkgeld wurde nicht rechtzeitig gewählt. Es wurde kein Geld bewegt – bitte erneut versuchen.',
76
+ terminalBusy: 'Das Terminal ist noch mit einem anderen Vorgang beschäftigt. Es wurde kein Geld bewegt – kurz warten und erneut versuchen.',
77
+ terminalBlocked: 'Das Terminal ist gesperrt. Es wurde kein Geld bewegt – bitte hobex kontaktieren.',
78
+ terminalSetup: 'Das Terminal ist nicht richtig eingerichtet. Es wurde kein Geld bewegt – bitte die Terminal-ID in den Einstellungen prüfen, sonst hobex kontaktieren.',
79
+ acquirerSetup: 'hobex nimmt dieses Terminal oder diesen Händler so nicht an. Es wurde kein Geld bewegt – bitte hobex kontaktieren.',
80
+ terminalFault: 'Das Terminal meldet eine Störung. Es wurde kein Geld bewegt – bitte das Terminal neu starten und erneut versuchen.',
81
+ requestRejected: 'Das Terminal hat die Anfrage abgewiesen. Es wurde kein Geld bewegt – tritt das wieder auf, bitte den Support kontaktieren.',
82
+ hostRejected: 'hobex hat die Zahlung abgewiesen. Es wurde kein Geld bewegt – bitte erneut versuchen; tritt das wieder auf, hobex kontaktieren.',
83
+ hostUnavailable: 'Die Bank oder hobex ist gerade nicht erreichbar. Es wurde kein Geld bewegt – bitte später erneut versuchen oder eine andere Zahlungsart verwenden.',
84
84
  invalidTransaction: 'Das Terminal kennt die ursprüngliche Zahlung nicht. Es wurde kein Geld bewegt.',
85
85
  refundPassword: 'Das Passwort für die Gutschrift war falsch oder wurde nicht eingegeben. Es wurde nichts ausgezahlt.',
86
- refundDisabled: 'Gutschriften sind an diesem Terminal abgeschaltet. Es wurde nichts ausgezahlt — bitte hobex kontaktieren.',
86
+ refundDisabled: 'Gutschriften sind an diesem Terminal abgeschaltet. Es wurde nichts ausgezahlt – bitte hobex kontaktieren.',
87
87
  refundRejected: 'Die Gutschrift wurde abgewiesen (Betrag zu hoch, bereits erstattet oder zu viele Versuche). Es wurde nichts ausgezahlt.',
88
- hostTimeoutReversed: 'hobex hat nicht rechtzeitig geantwortet, das Terminal hat den Vorgang selbst storniert. Es wird kein Geld bewegt — bitte erneut versuchen.',
89
- reversedByHost: 'Die Zahlung wurde wegen einer Störung automatisch storniert. Es wurde kein Geld bewegt — bitte erneut versuchen.',
90
- voidedAfterHostFault: 'hobex hat nicht sauber geantwortet, die Zahlung wurde deshalb sicherheitshalber storniert. Es wurde kein Geld bewegt — bitte erneut versuchen.',
91
- hostFault: 'Die Verbindung zwischen Terminal und hobex ist gestört. Ob die Karte belastet wurde, weiß das Terminal nicht — bitte nicht erneut kassieren, bevor es geklärt ist.',
92
- hostTimeout: 'hobex hat nicht rechtzeitig geantwortet. Ob die Karte belastet wurde, weiß das Terminal nicht — bitte nicht erneut kassieren, bevor es geklärt ist.',
93
- internalError: 'Das Terminal meldet einen internen Fehler. Ob die Karte belastet wurde, ist unklar — bitte nicht erneut kassieren, bevor es geklärt ist.',
88
+ hostTimeoutReversed: 'hobex hat nicht rechtzeitig geantwortet, das Terminal hat den Vorgang selbst storniert. Es wird kein Geld bewegt – bitte erneut versuchen.',
89
+ reversedByHost: 'Die Zahlung wurde wegen einer Störung automatisch storniert. Es wurde kein Geld bewegt – bitte erneut versuchen.',
90
+ voidedAfterHostFault: 'hobex hat nicht sauber geantwortet, die Zahlung wurde deshalb sicherheitshalber storniert. Es wurde kein Geld bewegt – bitte erneut versuchen.',
91
+ hostFault: 'Die Verbindung zwischen Terminal und hobex ist gestört. Ob die Karte belastet wurde, weiß das Terminal nicht – bitte nicht erneut kassieren, bevor es geklärt ist.',
92
+ hostTimeout: 'hobex hat nicht rechtzeitig geantwortet. Ob die Karte belastet wurde, weiß das Terminal nicht – bitte nicht erneut kassieren, bevor es geklärt ist.',
93
+ internalError: 'Das Terminal meldet einen internen Fehler. Ob die Karte belastet wurde, ist unklar – bitte nicht erneut kassieren, bevor es geklärt ist.',
94
94
  canceled: 'Die Zahlung ist aufgehoben.',
95
- cancelDenied: 'Die Zahlung lässt sich nicht mehr aufheben und bleibt belastet — bitte stattdessen eine Gutschrift ausführen.',
95
+ cancelDenied: 'Die Zahlung lässt sich nicht mehr aufheben und bleibt belastet – bitte stattdessen eine Gutschrift ausführen.',
96
96
  originalDeclined: 'Die ursprüngliche Zahlung war abgelehnt; es gibt nichts aufzuheben.',
97
97
  notAbortable: 'Der Vorgang ist bereits abgeschlossen und lässt sich nicht mehr abbrechen.',
98
98
  noStatement: 'Das Terminal hat zu diesem Vorgang keine Auskunft.',
@@ -303,16 +303,13 @@ function stripeBlock(daten, cardPaymentId) {
303
303
  return zeilen;
304
304
  }
305
305
  /**
306
- * Der Kartenzahlungsblock des Belegs -- fuer JEDEN Anbieter, den das Backend
307
- * kennt. Ohne `cardPaymentData` bleibt der Block weg; ein unbekannter Anbieter
308
- * ebenfalls, still und ohne Fehler: ein Beleg muss sich immer zeigen lassen.
306
+ * Der Kartenzahlungsblock eines Anbieters -- fuer JEDEN Anbieter, den das
307
+ * Backend kennt. Ein unbekannter Anbieter bekommt keinen Block, still und
308
+ * ohne Fehler: ein Beleg muss sich immer zeigen lassen.
309
309
  */
310
- function kartenblock(receipt) {
311
- const daten = receipt.cardPaymentData;
312
- if (daten == null)
313
- return [];
310
+ function anbieterBlock(provider, daten, id) {
314
311
  const zeilen = (() => {
315
- switch (receipt.creditCardProvider) {
312
+ switch (provider) {
316
313
  case 'hobexHps':
317
314
  case 'hobexCloudApi':
318
315
  return hobexBlock(daten);
@@ -324,7 +321,7 @@ function kartenblock(receipt) {
324
321
  case 'myposPro':
325
322
  return myposBlock(daten);
326
323
  case 'stripe':
327
- return stripeBlock(daten, receipt.cardPaymentId ?? null);
324
+ return stripeBlock(daten, id);
328
325
  default:
329
326
  return [];
330
327
  }
@@ -337,12 +334,117 @@ function kartenblock(receipt) {
337
334
  // gehoert aber zum Blatt, nicht zum Terminal.
338
335
  return [...zeilen, { kind: 'space', lines: 1 }];
339
336
  }
337
+ /**
338
+ * Die Kartenzahlungsbloecke des Belegs. Mit Zahlungsliste (`payments`) je
339
+ * Zahlung mit Anbieter und Terminaldaten ein Block, in Zahlungsreihenfolge --
340
+ * zwei Karten desselben Anbieters ergeben zwei Bloecke; die alten
341
+ * Einzelfelder zaehlen dann nicht. Bei mehreren Zahlungen steht vor jedem
342
+ * Block, nicht fett und zentriert, die Nummer der Zahlung aus der
343
+ * Aufschluesselung („2. Kartenzahlung") -- so ist jeder Block seiner Zeile
344
+ * zuzuordnen. Ohne (oder mit leerer) Liste der bisherige Weg ueber
345
+ * `creditCardProvider`/`cardPaymentData`/`cardPaymentId` -- ebenso bei
346
+ * hoechstens einer Zahlung ohne `providerData`, wenn die Altfelder gesetzt sind.
347
+ */
348
+ function kartenblock(receipt) {
349
+ const zahlungen = receipt.payments;
350
+ // Eine einzelne Zahlung ohne Terminaldaten neben gesetzten Altfeldern
351
+ // (creditCardProvider + cardPaymentData): der bisherige Block, wie ohne Liste.
352
+ const altfelderTragen = zahlungen != null && zahlungen.length <= 1
353
+ && zahlungen.every((z) => z.providerData == null)
354
+ && receipt.creditCardProvider != null && receipt.cardPaymentData != null;
355
+ if (zahlungen != null && zahlungen.length > 0 && !altfelderTragen) {
356
+ const zeilen = [];
357
+ zahlungen.forEach((zahlung, i) => {
358
+ if (zahlung.provider == null || zahlung.providerData == null)
359
+ return;
360
+ const block = anbieterBlock(zahlung.provider, zahlung.providerData, zahlung.providerPaymentId ?? null);
361
+ if (block.length === 0)
362
+ return;
363
+ if (zahlungen.length > 1)
364
+ zeilen.push(textZeile(zahlungNummerText(zahlung, i), 'center'));
365
+ zeilen.push(...block);
366
+ });
367
+ return zeilen;
368
+ }
369
+ const daten = receipt.cardPaymentData;
370
+ if (daten == null)
371
+ return [];
372
+ return anbieterBlock(receipt.creditCardProvider, daten, receipt.cardPaymentId ?? null);
373
+ }
340
374
  function zahlungsartText(wert) {
341
375
  if (wert != null && typeof wert === 'object') {
342
376
  return wert.label;
343
377
  }
344
378
  return typeof wert === 'string' ? wert : '';
345
379
  }
380
+ /** Barzahlarten -- Zwilling von `BAR_ZAHLARTEN` (functions/gemeinsam/tip-core.js). */
381
+ const BAR_ZAHLARTEN = ['cash', 'uberCash', 'boltCash'];
382
+ function zahlartSchluessel(wert) {
383
+ if (wert != null && typeof wert === 'object')
384
+ return wert.value;
385
+ return typeof wert === 'string' ? wert : '';
386
+ }
387
+ /**
388
+ * Nummerierter Text einer Zahlung („1. Kartenzahlung", „3. Barzahlung") --
389
+ * in der Aufschluesselung und ueber ihrem Kartenblock dieselbe Nummer, in
390
+ * Zahlungsreihenfolge ab 1.
391
+ */
392
+ function zahlungNummerText(zahlung, index) {
393
+ return `${index + 1}. ${zahlungsartText(zahlung.method)}`;
394
+ }
395
+ /** „davon Trinkgeld" eingerueckt unter einer Zahlung, die Trinkgeld traegt. */
396
+ function zahlungTrinkgeldZeilen(zahlung) {
397
+ if (typeof zahlung.tipCents !== 'number' || zahlung.tipCents <= 0)
398
+ return [];
399
+ return [paarZeile(' davon Trinkgeld', `${formatCents(zahlung.tipCents)} €`, 8, 4)];
400
+ }
401
+ /**
402
+ * Gegeben/Rueckgeld unter einer Barzahlung mit `tenderedCents`. Fehlt
403
+ * `changeCents` (der Server rechnet es sonst selbst), ergibt es sich aus
404
+ * gegeben minus Betrag.
405
+ */
406
+ function barZeilen(zahlung) {
407
+ if (!BAR_ZAHLARTEN.includes(zahlartSchluessel(zahlung.method)) || typeof zahlung.tenderedCents !== 'number')
408
+ return [];
409
+ const rueckgeld = typeof zahlung.changeCents === 'number' ? zahlung.changeCents : zahlung.tenderedCents - zahlung.amountCents;
410
+ return [
411
+ paarZeile(' Gegeben:', `${formatCents(zahlung.tenderedCents)} €`, 8, 4),
412
+ paarZeile(' Rückgeld:', `${formatCents(rueckgeld)} €`, 8, 4),
413
+ ];
414
+ }
415
+ /**
416
+ * Die Zahlungszeilen unter „Gesamt:".
417
+ *
418
+ * - Ohne Zahlungsliste: „Zahlungsart: <Label>" aus `paymentMethod`, wie immer.
419
+ * - Genau eine Zahlung: dieselbe Zeile, Label aus der Zahlung.
420
+ * - Mehrere Zahlungen (auch zwei Karten, die `paymentMethod: creditCard`
421
+ * ergeben -- entschieden wird an der Laenge, nie an `mixed`): „Zahlungsarten:"
422
+ * und je Zahlung eine nummerierte Zeile mit Betrag, ohne Anbieter (der
423
+ * steht im Kartenblock mit derselben Nummer). Breite 8:4 -- auf 58 mm
424
+ * bleiben der Betragsspalte elf Zeichen, genug fuer „-9999,99 €".
425
+ *
426
+ * Unter jeder Zahlung in dieser Reihenfolge: „davon Trinkgeld" (bei
427
+ * `tipCents`), dann bei einer Barzahlung mit gegebenem Betrag „Gegeben:" und
428
+ * „Rückgeld:" -- alles, was zu einer Zahlung gehoert, zwei Zeichen eingerueckt,
429
+ * die Zahlung selbst buendig.
430
+ */
431
+ function zahlungsZeilen(receipt) {
432
+ const zahlungen = receipt.payments;
433
+ if (zahlungen == null || zahlungen.length === 0) {
434
+ return [paarZeile('Zahlungsart:', zahlungsartText(receipt.paymentMethod))];
435
+ }
436
+ if (zahlungen.length === 1) {
437
+ const zahlung = zahlungen[0];
438
+ return [paarZeile('Zahlungsart:', zahlungsartText(zahlung.method)), ...zahlungTrinkgeldZeilen(zahlung), ...barZeilen(zahlung)];
439
+ }
440
+ const zeilen = [textZeile('Zahlungsarten:')];
441
+ zahlungen.forEach((zahlung, i) => {
442
+ zeilen.push(paarZeile(zahlungNummerText(zahlung, i), `${formatCents(zahlung.amountCents)} €`, 8, 4));
443
+ zeilen.push(...zahlungTrinkgeldZeilen(zahlung));
444
+ zeilen.push(...barZeilen(zahlung));
445
+ });
446
+ return zeilen;
447
+ }
346
448
  // -------------------------------------------------------- Kleinunternehmer
347
449
  /**
348
450
  * Hinweis auf die Steuerbefreiung, den ein Kleinunternehmerbeleg tragen muss —
@@ -910,7 +1012,7 @@ function buildReceiptLayout(receipt, company, options = {}) {
910
1012
  lines.push({ kind: 'rule', char: '-' });
911
1013
  }
912
1014
  lines.push(paarZeile('Gesamt:', `${formatCents(summeCents)} €`));
913
- lines.push(paarZeile('Zahlungsart:', zahlungsartText(receipt.paymentMethod)));
1015
+ lines.push(...zahlungsZeilen(receipt));
914
1016
  lines.push({ kind: 'space', lines: 1 });
915
1017
  // --- Rechtshinweise und Ausfallhinweis
916
1018
  const hinweise = company.isSmallBusiness
@@ -3,7 +3,7 @@ import { type CreateStripeLinkOptions, type StripeCaptureResult } from '../payme
3
3
  import { type HobexPayOptions, type HobexRefundOptions } from '../payments/hobex.js';
4
4
  import { type TransportOptions } from './transport.js';
5
5
  import { type CashboxStatus, type SignatureStatus } from './status.js';
6
- import { type SendReceiptEmailOptions, type SendReceiptEmailResult, type ListMyReceiptsOptions, type ReceiptList, type ReceiptWithCompany, type SellReceiptOptions, type CancelReceiptOptions, type CancelReceiptResult, type CreateCancelReceiptOptions } from './receipts.js';
6
+ import { type SendReceiptEmailOptions, type SendReceiptEmailResult, type ListMyReceiptsOptions, type ReceiptList, type ReceiptWithCompany, type SellReceiptOptions, type SellReceiptWithPaymentsOptions, type CancelReceiptOptions, type CancelReceiptResult, type CreateCancelReceiptOptions } from './receipts.js';
7
7
  /**
8
8
  * Schlichte Factory ueber den Endpunkt-Funktionen: bindet einen Transport
9
9
  * einmal und liefert die Aufrufe ohne den wiederkehrenden ersten Parameter.
@@ -30,9 +30,9 @@ import { type SendReceiptEmailOptions, type SendReceiptEmailResult, type ListMyR
30
30
  */
31
31
  export interface KasseneckApi {
32
32
  /** Normalbeleg (Verkauf). */
33
- sellReceipt(options: SellReceiptOptions): Promise<Receipt>;
33
+ sellReceipt(options: SellReceiptOptions | SellReceiptWithPaymentsOptions): Promise<Receipt>;
34
34
  /** Normalbeleg samt Firmen-/Druckdaten fuer den Belegdruck. */
35
- sellReceiptWithCompany(options: SellReceiptOptions): Promise<ReceiptWithCompany>;
35
+ sellReceiptWithCompany(options: SellReceiptOptions | SellReceiptWithPaymentsOptions): Promise<ReceiptWithCompany>;
36
36
  /** Storno eines bestehenden Belegs — voll oder in Teilen, ueber den Storno-Endpunkt. */
37
37
  cancelReceipt(options: CancelReceiptOptions): Promise<CancelReceiptResult>;
38
38
  /** Storno aus frei uebergebenen Positionen. */
@@ -2,7 +2,7 @@ export { type AuthCredentials, type KasseneckAuth, type ApiKeyAuthOptions, type
2
2
  export { DEFAULT_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
3
  export { AUFRUFE, type Aufruf, } from './aufrufe.js';
4
4
  export { KasseneckApiError, KasseneckAuthError, KasseneckHttpError, KasseneckNetworkError, KasseneckValidationError, type ValidationScope, type KasseneckError, type HttpFailureReason, type CauseDigest, isKasseneckApiError, isKasseneckAuthError, isKasseneckHttpError, isKasseneckNetworkError, isKasseneckValidationError, } from './errors.js';
5
- export { type ReceiptCommonOptions, type SellReceiptOptions, type TipOptions, type TipRecipientShare, type CancelReceiptOptions, type CreateCancelReceiptOptions, type ReceiptWithCompany, sellReceipt, sellReceiptWithCompany, cancelReceipt, type CancelReceiptResult, createCancelReceipt, zeroReceipt, getReceipt, getReceiptWithCompany, generateFullReceiptId, getFirstReceiptDate, listMyReceipts, type ListMyReceiptsOptions, type ReceiptList, type ReceiptListStats, checkVoucherCombinationError, type SendReceiptEmailOptions, type SendReceiptEmailResult, sendReceiptEmail, } from './receipts.js';
5
+ export { type ReceiptCommonOptions, type SellReceiptOptions, type SellReceiptWithPaymentsOptions, type TipOptions, type TipRecipientShare, type CancelReceiptOptions, type CreateCancelReceiptOptions, type ReceiptWithCompany, sellReceipt, sellReceiptWithCompany, cancelReceipt, type CancelReceiptResult, createCancelReceipt, 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';
7
7
  export { downloadDailyReport, downloadMonthlyReport } from './reports.js';
8
8
  export { type CashboxStatus, type SignatureStatus, getCashboxStatus, getSignatureStatus, } from './status.js';
@@ -1,5 +1,5 @@
1
1
  import { ReceiptType, type ReceiptTypeKey, KeckPaymentMethod, type KeckPaymentMethodKey, CreditCardProvider } from '../enums/index.js';
2
- import { type Receipt, type ReceiptCompany, type ReceiptItem, type Voucher, type ReceiptSummary, type ReportMonth, type CancellationItem, type CancellationOf, type CancellationReason } from '../models/index.js';
2
+ import { type Receipt, type ReceiptCompany, type ReceiptItem, type Voucher, type ReceiptSummary, type ReportMonth, type CancellationItem, type CancellationOf, type CancellationReason, type ReceiptPaymentInput } from '../models/index.js';
3
3
  import type { InternerTransport } from './aufrufe.js';
4
4
  import type { Pruefangaben, ReceiptLayout } from '../receipt/layout.js';
5
5
  import type { LogoStufe } from '../receipt/blatt.js';
@@ -90,11 +90,32 @@ export interface CreateReceiptOptions extends ReceiptCommonOptions {
90
90
  * ausdruecklich uebergebene `paymentMethod` sticht.
91
91
  */
92
92
  paymentMethodFromServer?: string;
93
+ /**
94
+ * Mehrere Zahlungen je Beleg (siehe [ReceiptPaymentInput]). Schliesst
95
+ * `paymentMethod`, `paymentMethodFromServer` und die Kartenfelder aus —
96
+ * die Kartenangaben gehoeren dann in die einzelne Zahlung (Backend:
97
+ * `PAYMENTS_CONFLICT`). Nur bei `standard` und `training`.
98
+ */
99
+ payments?: ReceiptPaymentInput[];
93
100
  items?: ReceiptItem[];
94
101
  vouchers?: Voucher[];
95
102
  }
103
+ /** Verkauf mit einer Zahlungsart (`paymentMethod`, Kartenfelder aus [ReceiptCommonOptions]). */
96
104
  export interface SellReceiptOptions extends ReceiptCommonOptions {
97
105
  paymentMethod: KeckPaymentMethod | KeckPaymentMethodKey;
106
+ payments?: undefined;
107
+ items?: ReceiptItem[];
108
+ vouchers?: Voucher[];
109
+ }
110
+ /**
111
+ * Verkauf mit mehreren Zahlungen (`payments`, siehe [ReceiptPaymentInput]).
112
+ * Ohne `paymentMethod` und ohne die Kartenfelder aus [ReceiptCommonOptions] —
113
+ * die Kartenangaben stehen in der einzelnen Zahlung (Backend:
114
+ * `PAYMENTS_CONFLICT`, zur Laufzeit ebenso geprueft).
115
+ */
116
+ export interface SellReceiptWithPaymentsOptions extends ReceiptCommonOptions {
117
+ payments: ReceiptPaymentInput[];
118
+ paymentMethod?: undefined;
98
119
  items?: ReceiptItem[];
99
120
  vouchers?: Voucher[];
100
121
  }
@@ -126,6 +147,14 @@ export type CancelReceiptOptions = {
126
147
  creditCardProvider?: CreditCardProvider;
127
148
  cardPaymentId?: string;
128
149
  cardPaymentData?: Record<string, unknown>;
150
+ /**
151
+ * Rueckzahlung je Zahlung (Betraege negativ, `refundOf` = `id` der
152
+ * Originalzahlung). Schliesst `paymentMethod` und die Kartenfelder aus
153
+ * (Backend: `PAYMENTS_CONFLICT`). Ohne Angabe spiegelt der Server die
154
+ * Restbetraege jeder Originalzahlung; ein Teilstorno eines Belegs mit
155
+ * mehreren Zahlungen braucht sie (`STORNO_PAYMENTS_REQUIRED`).
156
+ */
157
+ payments?: ReceiptPaymentInput[];
129
158
  } & ({
130
159
  receipt: Receipt;
131
160
  cashregisterId?: string;
@@ -183,12 +212,12 @@ export interface ReceiptWithCompany {
183
212
  */
184
213
  export declare function createReceipt(rufen: InternerTransport, options: CreateReceiptOptions): Promise<Receipt>;
185
214
  /** Normalbeleg (Verkauf) nach RKSV. */
186
- export declare function sellReceipt(rufen: InternerTransport, options: SellReceiptOptions): Promise<Receipt>;
215
+ export declare function sellReceipt(rufen: InternerTransport, options: SellReceiptOptions | SellReceiptWithPaymentsOptions): Promise<Receipt>;
187
216
  /**
188
217
  * Normalbeleg wie [sellReceipt], liefert zusaetzlich die Firmen-/Druckdaten
189
218
  * aus derselben Antwort — alles, was ein Belegdruck braucht, in einem Aufruf.
190
219
  */
191
- export declare function sellReceiptWithCompany(rufen: InternerTransport, options: SellReceiptOptions): Promise<ReceiptWithCompany>;
220
+ export declare function sellReceiptWithCompany(rufen: InternerTransport, options: SellReceiptOptions | SellReceiptWithPaymentsOptions): Promise<ReceiptWithCompany>;
192
221
  /**
193
222
  * Storno-Beleg zu einem bestehenden Beleg — voll oder in Teilen. Prueft die
194
223
  * Eingabe, bevor etwas hinausgeht; der Server haelt die Restmengen und die