@kreiseck/kasseneck-api 0.29.0 → 0.30.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.
- package/CHANGELOG.md +43 -0
- package/dist/cjs/client/api.d.ts +3 -3
- package/dist/cjs/client/index.d.ts +1 -1
- package/dist/cjs/client/receipts.d.ts +32 -3
- package/dist/cjs/client/receipts.js +121 -6
- package/dist/cjs/enums/keck-payment-method.d.ts +10 -0
- package/dist/cjs/enums/keck-payment-method.js +6 -0
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js +6 -2
- package/dist/cjs/models/cancellation.d.ts +11 -1
- package/dist/cjs/models/cancellation.js +15 -0
- package/dist/cjs/models/index.d.ts +2 -0
- package/dist/cjs/models/index.js +7 -1
- package/dist/cjs/models/payment-errors.d.ts +22 -0
- package/dist/cjs/models/payment-errors.js +46 -0
- package/dist/cjs/models/receipt-payment.d.ts +85 -0
- package/dist/cjs/models/receipt-payment.js +40 -0
- package/dist/cjs/models/receipt-summary.d.ts +9 -0
- package/dist/cjs/models/receipt-summary.js +2 -0
- package/dist/cjs/models/receipt.d.ts +9 -0
- package/dist/cjs/models/receipt.js +3 -0
- package/dist/cjs/receipt/layout.js +112 -10
- package/dist/esm/client/api.d.ts +3 -3
- package/dist/esm/client/index.d.ts +1 -1
- package/dist/esm/client/receipts.d.ts +32 -3
- package/dist/esm/client/receipts.js +121 -6
- package/dist/esm/enums/keck-payment-method.d.ts +10 -0
- package/dist/esm/enums/keck-payment-method.js +6 -0
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +1 -1
- package/dist/esm/models/cancellation.d.ts +11 -1
- package/dist/esm/models/cancellation.js +15 -0
- package/dist/esm/models/index.d.ts +2 -0
- package/dist/esm/models/index.js +2 -0
- package/dist/esm/models/payment-errors.d.ts +22 -0
- package/dist/esm/models/payment-errors.js +42 -0
- package/dist/esm/models/receipt-payment.d.ts +85 -0
- package/dist/esm/models/receipt-payment.js +36 -0
- package/dist/esm/models/receipt-summary.d.ts +9 -0
- package/dist/esm/models/receipt-summary.js +2 -0
- package/dist/esm/models/receipt.d.ts +9 -0
- package/dist/esm/models/receipt.js +3 -0
- package/dist/esm/receipt/layout.js +112 -10
- package/fixtures/belege/split-bar-rueckgeld.json +58 -0
- package/fixtures/belege/split-eine-karte-trinkgeld.json +75 -0
- package/fixtures/belege/split-karte-karte-bar.json +102 -0
- package/fixtures/belege/split-langer-betrag.json +74 -0
- package/fixtures/belege/split-tischrunde-trinkgeld.json +152 -0
- package/fixtures/belege/split-trinkgeld-karte.json +82 -0
- package/fixtures/belege/split-zwei-karten-gleicher-anbieter.json +89 -0
- package/fixtures/belege/storno-split-teil.json +71 -0
- package/fixtures/belege/storno-split-voll.json +100 -0
- package/fixtures/erwartet/split-bar-rueckgeld.blatt32.json +194 -0
- package/fixtures/erwartet/split-bar-rueckgeld.blatt48.json +182 -0
- package/fixtures/erwartet/split-bar-rueckgeld.grid32.txt +28 -0
- package/fixtures/erwartet/split-bar-rueckgeld.grid48.txt +26 -0
- package/fixtures/erwartet/split-bar-rueckgeld.lines.json +286 -0
- package/fixtures/erwartet/split-eine-karte-trinkgeld.blatt32.json +242 -0
- package/fixtures/erwartet/split-eine-karte-trinkgeld.blatt48.json +224 -0
- package/fixtures/erwartet/split-eine-karte-trinkgeld.grid32.txt +36 -0
- package/fixtures/erwartet/split-eine-karte-trinkgeld.grid48.txt +33 -0
- package/fixtures/erwartet/split-eine-karte-trinkgeld.lines.json +371 -0
- package/fixtures/erwartet/split-karte-karte-bar.blatt32.json +356 -0
- package/fixtures/erwartet/split-karte-karte-bar.blatt48.json +338 -0
- package/fixtures/erwartet/split-karte-karte-bar.grid32.txt +55 -0
- package/fixtures/erwartet/split-karte-karte-bar.grid48.txt +52 -0
- package/fixtures/erwartet/split-karte-karte-bar.lines.json +519 -0
- package/fixtures/erwartet/split-langer-betrag.blatt32.json +266 -0
- package/fixtures/erwartet/split-langer-betrag.blatt48.json +260 -0
- package/fixtures/erwartet/split-langer-betrag.grid32.txt +40 -0
- package/fixtures/erwartet/split-langer-betrag.grid48.txt +39 -0
- package/fixtures/erwartet/split-langer-betrag.lines.json +343 -0
- package/fixtures/erwartet/split-tischrunde-trinkgeld.blatt32.json +470 -0
- package/fixtures/erwartet/split-tischrunde-trinkgeld.blatt48.json +434 -0
- package/fixtures/erwartet/split-tischrunde-trinkgeld.grid32.txt +74 -0
- package/fixtures/erwartet/split-tischrunde-trinkgeld.grid48.txt +68 -0
- package/fixtures/erwartet/split-tischrunde-trinkgeld.lines.json +740 -0
- package/fixtures/erwartet/split-trinkgeld-karte.blatt32.json +272 -0
- package/fixtures/erwartet/split-trinkgeld-karte.blatt48.json +254 -0
- package/fixtures/erwartet/split-trinkgeld-karte.grid32.txt +41 -0
- package/fixtures/erwartet/split-trinkgeld-karte.grid48.txt +38 -0
- package/fixtures/erwartet/split-trinkgeld-karte.lines.json +428 -0
- package/fixtures/erwartet/split-zwei-karten-gleicher-anbieter.blatt32.json +326 -0
- package/fixtures/erwartet/split-zwei-karten-gleicher-anbieter.blatt48.json +296 -0
- package/fixtures/erwartet/split-zwei-karten-gleicher-anbieter.grid32.txt +50 -0
- package/fixtures/erwartet/split-zwei-karten-gleicher-anbieter.grid48.txt +45 -0
- package/fixtures/erwartet/split-zwei-karten-gleicher-anbieter.lines.json +504 -0
- package/fixtures/erwartet/storno-split-teil.blatt32.json +230 -0
- package/fixtures/erwartet/storno-split-teil.blatt48.json +224 -0
- package/fixtures/erwartet/storno-split-teil.grid32.txt +34 -0
- package/fixtures/erwartet/storno-split-teil.grid48.txt +33 -0
- package/fixtures/erwartet/storno-split-teil.lines.json +304 -0
- package/fixtures/erwartet/storno-split-voll.blatt32.json +320 -0
- package/fixtures/erwartet/storno-split-voll.blatt48.json +314 -0
- package/fixtures/erwartet/storno-split-voll.grid32.txt +49 -0
- package/fixtures/erwartet/storno-split-voll.grid48.txt +48 -0
- package/fixtures/erwartet/storno-split-voll.lines.json +410 -0
- package/fixtures/hobex-hps-codes.json +1 -1
- package/fixtures/kasse-texte.json +1 -1
- package/fixtures/manifest.json +72 -0
- package/fixtures/oberflaeche.json +1 -1
- package/fixtures/rechnung-api.schema.json +1 -1
- package/fixtures/rechnung-texte.json +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,85 @@
|
|
|
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, hoechstens an einer Zahlung.
|
|
61
|
+
* - `provider`/`providerPaymentId`/`providerData`: bei Karten Pflicht
|
|
62
|
+
* (`providerPaymentId` ausser bei `custom`), bei `online` optional, sonst
|
|
63
|
+
* nicht erlaubt; am Storno beschreiben sie die Erstattung und sind optional.
|
|
64
|
+
* - `refundOf`: nur am Storno.
|
|
65
|
+
* - `tipCents`: Trinkgeld dieser Zahlung, ganze Cent > 0, Teil von
|
|
66
|
+
* `amountCents`; nur am Verkauf, nie neben `tip` (den Rest prueft der Server).
|
|
67
|
+
*/
|
|
68
|
+
export interface ReceiptPaymentInput {
|
|
69
|
+
method: KeckPaymentMethod | KeckPaymentMethodKey;
|
|
70
|
+
amountCents: number;
|
|
71
|
+
tenderedCents?: number;
|
|
72
|
+
provider?: CreditCardProvider;
|
|
73
|
+
providerPaymentId?: string;
|
|
74
|
+
providerData?: Record<string, unknown>;
|
|
75
|
+
refundOf?: string;
|
|
76
|
+
tipCents?: number;
|
|
77
|
+
}
|
|
78
|
+
/** Lesepfad: nur vorhandene Felder uebernehmen, nichts ergaenzen. */
|
|
79
|
+
export declare function fromReceiptPaymentPayload(payload: ReceiptPaymentPayload): ReceiptPayment;
|
|
80
|
+
/**
|
|
81
|
+
* Schreibpfad: Zahlungen zurueck in die Nutzlast — streng wie
|
|
82
|
+
* `toReceiptPayload`: ein roher, unbekannter Schluessel bei `method` oder
|
|
83
|
+
* `provider` wirft.
|
|
84
|
+
*/
|
|
85
|
+
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) {
|
|
@@ -303,16 +303,13 @@ function stripeBlock(daten, cardPaymentId) {
|
|
|
303
303
|
return zeilen;
|
|
304
304
|
}
|
|
305
305
|
/**
|
|
306
|
-
* Der Kartenzahlungsblock
|
|
307
|
-
* kennt.
|
|
308
|
-
*
|
|
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
|
|
311
|
-
const daten = receipt.cardPaymentData;
|
|
312
|
-
if (daten == null)
|
|
313
|
-
return [];
|
|
310
|
+
function anbieterBlock(provider, daten, id) {
|
|
314
311
|
const zeilen = (() => {
|
|
315
|
-
switch (
|
|
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,
|
|
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(
|
|
1015
|
+
lines.push(...zahlungsZeilen(receipt));
|
|
914
1016
|
lines.push({ kind: 'space', lines: 1 });
|
|
915
1017
|
// --- Rechtshinweise und Ausfallhinweis
|
|
916
1018
|
const hinweise = company.isSmallBusiness
|
package/dist/esm/client/api.d.ts
CHANGED
|
@@ -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
|
|
@@ -50,6 +50,22 @@ function createReceiptParams(options) {
|
|
|
50
50
|
if (items != null && items.length > 0) {
|
|
51
51
|
params['items'] = alsNutzlast(items, toReceiptItemPayload);
|
|
52
52
|
}
|
|
53
|
+
// `payments: null` gilt wie im Backend (zahlungs-eingang.js) als nicht angegeben.
|
|
54
|
+
if (options.payments != null) {
|
|
55
|
+
// Der alte Storno-Weg und der Null-/Startbeleg nehmen keine Zahlungsliste
|
|
56
|
+
// (Backend: PAYMENTS_NOT_ALLOWED); ein Storno mit mehreren Zahlungen
|
|
57
|
+
// laeuft ueber cancelReceipt.
|
|
58
|
+
if (typ.value === ReceiptType.cancellation.value) {
|
|
59
|
+
throw eingabefehler('payments am Storno gehen nur ueber cancelReceipt.');
|
|
60
|
+
}
|
|
61
|
+
if (typ.value !== ReceiptType.standard.value && typ.value !== ReceiptType.training.value) {
|
|
62
|
+
throw eingabefehler(`payments sind bei receiptType "${typ.value}" nicht erlaubt.`);
|
|
63
|
+
}
|
|
64
|
+
const konflikt = zahlungsKonflikt(options);
|
|
65
|
+
if (konflikt != null)
|
|
66
|
+
throw eingabefehler(konflikt);
|
|
67
|
+
params['payments'] = gepruefteZahlungen(options.payments, false, 'createReceipt');
|
|
68
|
+
}
|
|
53
69
|
// Vom Aufrufer kommt sie geprueft, vom Server roh — siehe die beiden Felder
|
|
54
70
|
// in [CreateReceiptOptions]. Die Typpruefung allein reicht dafuer nicht: ein
|
|
55
71
|
// Verbraucher ohne Typen faellt durch dieses Netz, und ein Tippfehler in der
|
|
@@ -133,11 +149,15 @@ export async function cancelReceipt(rufen, options) {
|
|
|
133
149
|
if (options.note !== undefined && options.note.length > NOTE_MAX) {
|
|
134
150
|
throw new KasseneckValidationError('cancelReceipt', `Anmerkung ist zu lang (hoechstens ${NOTE_MAX} Zeichen)`, 'request');
|
|
135
151
|
}
|
|
152
|
+
// `payments: null` gilt wie im Backend als nicht angegeben.
|
|
153
|
+
const zahlungen = options.payments != null ? gepruefteStornoZahlungen(options) : undefined;
|
|
136
154
|
const params = { cashregisterId, originalReceiptId, reason: options.reason };
|
|
137
155
|
if (options.items !== undefined)
|
|
138
156
|
params.items = options.items.map((p) => ({ index: p.index, quantity: p.quantity }));
|
|
139
157
|
if (options.note !== undefined && options.note !== '')
|
|
140
158
|
params.note = options.note;
|
|
159
|
+
if (zahlungen !== undefined)
|
|
160
|
+
params.payments = zahlungen;
|
|
141
161
|
if (options.paymentMethod != null)
|
|
142
162
|
params.paymentMethod = gepruefteZahlungsart(options.paymentMethod);
|
|
143
163
|
const karte = options.creditCardProvider != null || options.cardPaymentId != null || options.cardPaymentData != null;
|
|
@@ -491,15 +511,110 @@ function gepruefterTip(tip) {
|
|
|
491
511
|
}
|
|
492
512
|
return nutzlast;
|
|
493
513
|
}
|
|
494
|
-
/**
|
|
514
|
+
/**
|
|
515
|
+
* Zahlungsart des Aufrufers pruefen — unbekannt wirft, bevor etwas rausgeht.
|
|
516
|
+
* `mixed` wirft ebenfalls: den Wert vergibt nur der Server (Beleg mit
|
|
517
|
+
* mehreren Zahlarten); gesendet wird stattdessen die Zahlungsliste.
|
|
518
|
+
*/
|
|
495
519
|
function gepruefteZahlungsart(wert) {
|
|
496
|
-
|
|
497
|
-
|
|
520
|
+
let zahlungsart;
|
|
521
|
+
if (typeof wert === 'object' && wert !== null) {
|
|
522
|
+
zahlungsart = wert.value;
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
if (typeof wert !== 'string' || !Object.prototype.hasOwnProperty.call(KeckPaymentMethod, wert)) {
|
|
526
|
+
throw eingabefehler(`Zahlungsart: unbekannter Schluessel "${String(wert)}"`);
|
|
527
|
+
}
|
|
528
|
+
zahlungsart = KeckPaymentMethod[wert].value;
|
|
498
529
|
}
|
|
499
|
-
if (
|
|
500
|
-
throw eingabefehler(
|
|
530
|
+
if (zahlungsart === KeckPaymentMethod.mixed.value) {
|
|
531
|
+
throw eingabefehler('Zahlungsart "mixed" vergibt nur der Server – mehrere Zahlarten gehen als payments hinaus.');
|
|
501
532
|
}
|
|
502
|
-
return
|
|
533
|
+
return zahlungsart;
|
|
534
|
+
}
|
|
535
|
+
/** Hoechstzahl der Zahlungen je Beleg (Backend: MAX_ZAHLUNGEN). */
|
|
536
|
+
const MAX_ZAHLUNGEN = 20;
|
|
537
|
+
/**
|
|
538
|
+
* `payments` neben einer Einzel-Zahlungsart oder Kartenfeldern? Liefert den
|
|
539
|
+
* Grund (Backend: PAYMENTS_CONFLICT), sonst null. Nie still eines bevorzugen.
|
|
540
|
+
*/
|
|
541
|
+
function zahlungsKonflikt(options) {
|
|
542
|
+
for (const feld of ['paymentMethod', 'paymentMethodFromServer', 'creditCardProvider', 'cardPaymentId', 'cardPaymentData']) {
|
|
543
|
+
if (options[feld] != null) {
|
|
544
|
+
return `payments und ${feld} duerfen nicht gemeinsam gesendet werden – Kartenangaben gehoeren in die Zahlung.`;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return null;
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Zahlungsliste pruefen und in Nutzlast-Form bringen — Formpruefung wie
|
|
551
|
+
* `pruefeZahlungen` im Backend, soweit sie ohne Beleg und Zahlbetrag geht
|
|
552
|
+
* (Summe, Anbieter-Pflicht und Trinkgeld prueft der Server). Wirft, bevor
|
|
553
|
+
* etwas hinausgeht.
|
|
554
|
+
*/
|
|
555
|
+
function gepruefteZahlungen(roh, storno, functionName) {
|
|
556
|
+
const fehler = (grund) => new KasseneckValidationError(functionName, grund, 'request');
|
|
557
|
+
if (!Array.isArray(roh))
|
|
558
|
+
throw fehler('payments muss eine Liste sein.');
|
|
559
|
+
if (roh.length > MAX_ZAHLUNGEN)
|
|
560
|
+
throw fehler(`payments: es sind hoechstens ${MAX_ZAHLUNGEN} Eintraege erlaubt.`);
|
|
561
|
+
return roh.map((eintrag, i) => {
|
|
562
|
+
const nr = i + 1;
|
|
563
|
+
if (eintrag == null || typeof eintrag !== 'object' || Array.isArray(eintrag)) {
|
|
564
|
+
throw fehler(`Zahlung ${nr}: kein gueltiges Objekt.`);
|
|
565
|
+
}
|
|
566
|
+
const z = eintrag;
|
|
567
|
+
const method = gepruefteZahlungsart(z['method']);
|
|
568
|
+
const betrag = z['amountCents'];
|
|
569
|
+
if (typeof betrag !== 'number' || !Number.isInteger(betrag) || (storno ? betrag >= 0 : betrag <= 0)) {
|
|
570
|
+
throw fehler(`Zahlung ${nr}: amountCents muss eine ganze Zahl ${storno ? 'kleiner' : 'groesser'} als 0 sein.`);
|
|
571
|
+
}
|
|
572
|
+
const aus = { method, amountCents: betrag };
|
|
573
|
+
if (z['tenderedCents'] !== undefined) {
|
|
574
|
+
const gegeben = z['tenderedCents'];
|
|
575
|
+
if (storno || typeof gegeben !== 'number' || !Number.isInteger(gegeben) || gegeben < betrag) {
|
|
576
|
+
throw fehler(`Zahlung ${nr}: tenderedCents muss eine ganze Zahl von mindestens amountCents sein (nur am Verkauf).`);
|
|
577
|
+
}
|
|
578
|
+
aus['tenderedCents'] = gegeben;
|
|
579
|
+
}
|
|
580
|
+
if (z['tipCents'] !== undefined) {
|
|
581
|
+
const trinkgeld = z['tipCents'];
|
|
582
|
+
if (typeof trinkgeld !== 'number' || !Number.isInteger(trinkgeld) || trinkgeld <= 0) {
|
|
583
|
+
throw fehler(`Zahlung ${nr}: tipCents muss eine ganze Zahl groesser als 0 sein.`);
|
|
584
|
+
}
|
|
585
|
+
aus['tipCents'] = trinkgeld;
|
|
586
|
+
}
|
|
587
|
+
if (z['provider'] !== undefined) {
|
|
588
|
+
aus['provider'] = kartenanbieter(String(z['provider']));
|
|
589
|
+
}
|
|
590
|
+
if (z['providerPaymentId'] !== undefined) {
|
|
591
|
+
if (typeof z['providerPaymentId'] !== 'string' || z['providerPaymentId'] === '') {
|
|
592
|
+
throw fehler(`Zahlung ${nr}: providerPaymentId muss ein nicht-leerer Text sein.`);
|
|
593
|
+
}
|
|
594
|
+
aus['providerPaymentId'] = z['providerPaymentId'];
|
|
595
|
+
}
|
|
596
|
+
if (z['providerData'] !== undefined) {
|
|
597
|
+
const daten = z['providerData'];
|
|
598
|
+
if (daten === null || typeof daten !== 'object' || Array.isArray(daten)) {
|
|
599
|
+
throw fehler(`Zahlung ${nr}: providerData muss ein Objekt sein.`);
|
|
600
|
+
}
|
|
601
|
+
aus['providerData'] = daten;
|
|
602
|
+
}
|
|
603
|
+
if (z['refundOf'] !== undefined) {
|
|
604
|
+
if (!storno || typeof z['refundOf'] !== 'string' || z['refundOf'] === '') {
|
|
605
|
+
throw fehler(`Zahlung ${nr}: refundOf gibt es nur am Storno, als id der Originalzahlung.`);
|
|
606
|
+
}
|
|
607
|
+
aus['refundOf'] = z['refundOf'];
|
|
608
|
+
}
|
|
609
|
+
return aus;
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
/** `payments` am Storno: Konflikt mit Zahlungsart/Kartenfeldern, dann Form. */
|
|
613
|
+
function gepruefteStornoZahlungen(options) {
|
|
614
|
+
const konflikt = zahlungsKonflikt(options);
|
|
615
|
+
if (konflikt != null)
|
|
616
|
+
throw new KasseneckValidationError('cancelReceipt', konflikt, 'request');
|
|
617
|
+
return gepruefteZahlungen(options.payments, true, 'cancelReceipt');
|
|
503
618
|
}
|
|
504
619
|
/** Kartenanbieter pruefen — er stammt vom Aufrufer, nicht aus Serverdaten. */
|
|
505
620
|
function kartenanbieter(wert) {
|