@kreiseck/kasseneck-api 0.6.45 → 0.6.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -15
- package/dist/cjs/client/aufrufe.d.ts +1 -1
- package/dist/cjs/client/aufrufe.js +2 -0
- package/dist/cjs/client/errors.d.ts +7 -1
- package/dist/cjs/client/errors.js +8 -1
- package/dist/cjs/client/receipts.d.ts +16 -0
- package/dist/cjs/client/receipts.js +10 -0
- package/dist/cjs/client/transport.js +5 -4
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +4 -2
- package/dist/cjs/kasse/index.d.ts +1 -0
- package/dist/cjs/kasse/index.js +3 -0
- package/dist/cjs/kasse/trinkgeld.d.ts +10 -0
- package/dist/cjs/kasse/trinkgeld.js +27 -0
- package/dist/cjs/models/cancellation.d.ts +22 -0
- package/dist/cjs/models/cancellation.js +31 -1
- package/dist/cjs/models/hobex-receipt.js +9 -2
- package/dist/cjs/models/index.d.ts +1 -1
- package/dist/cjs/models/index.js +3 -1
- package/dist/cjs/models/receipt.js +3 -0
- package/dist/cjs/models/voucher.js +18 -2
- package/dist/cjs/payments/hobex-hps/connect-client.d.ts +104 -0
- package/dist/cjs/payments/hobex-hps/connect-client.js +159 -0
- package/dist/cjs/payments/hobex-hps/errors.d.ts +122 -0
- package/dist/cjs/payments/hobex-hps/errors.js +158 -0
- package/dist/cjs/payments/hobex-hps/events.d.ts +22 -0
- package/dist/cjs/payments/hobex-hps/events.js +2 -0
- package/dist/cjs/payments/hobex-hps/index.d.ts +27 -0
- package/dist/cjs/payments/hobex-hps/index.js +66 -0
- package/dist/cjs/payments/hobex-hps/outcome.d.ts +31 -0
- package/dist/cjs/payments/hobex-hps/outcome.js +7 -0
- package/dist/cjs/payments/hobex-hps/payments.d.ts +149 -0
- package/dist/cjs/payments/hobex-hps/payments.js +550 -0
- package/dist/cjs/payments/hobex-hps/receipt.d.ts +28 -0
- package/dist/cjs/payments/hobex-hps/receipt.js +60 -0
- package/dist/cjs/payments/hobex-hps/transaction-id.d.ts +65 -0
- package/dist/cjs/payments/hobex-hps/transaction-id.js +91 -0
- package/dist/cjs/payments/hobex-hps/transaction-response.d.ts +163 -0
- package/dist/cjs/payments/hobex-hps/transaction-response.js +245 -0
- package/dist/cjs/payments/hobex.js +9 -6
- package/dist/cjs/payments/index.d.ts +26 -14
- package/dist/cjs/payments/index.js +59 -15
- package/dist/cjs/printing/index.d.ts +1 -1
- package/dist/cjs/printing/index.js +2 -1
- package/dist/cjs/printing/webusb.d.ts +37 -7
- package/dist/cjs/printing/webusb.js +76 -18
- package/dist/cjs/receipt/epos.d.ts +18 -0
- package/dist/cjs/receipt/epos.js +78 -6
- package/dist/cjs/receipt/index.d.ts +1 -1
- package/dist/cjs/receipt/index.js +2 -1
- package/dist/cjs/register/index.d.ts +1 -1
- package/dist/cjs/register/index.js +2 -1
- package/dist/cjs/register/pairing.d.ts +67 -1
- package/dist/cjs/register/pairing.js +59 -3
- package/dist/esm/client/aufrufe.d.ts +1 -1
- package/dist/esm/client/aufrufe.js +2 -0
- package/dist/esm/client/errors.d.ts +7 -1
- package/dist/esm/client/errors.js +8 -1
- package/dist/esm/client/receipts.d.ts +16 -0
- package/dist/esm/client/receipts.js +10 -0
- package/dist/esm/client/transport.js +5 -4
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/kasse/index.d.ts +1 -0
- package/dist/esm/kasse/index.js +1 -0
- package/dist/esm/kasse/trinkgeld.d.ts +10 -0
- package/dist/esm/kasse/trinkgeld.js +24 -0
- package/dist/esm/models/cancellation.d.ts +22 -0
- package/dist/esm/models/cancellation.js +29 -0
- package/dist/esm/models/hobex-receipt.js +10 -3
- package/dist/esm/models/index.d.ts +1 -1
- package/dist/esm/models/index.js +1 -1
- package/dist/esm/models/receipt.js +3 -0
- package/dist/esm/models/voucher.js +18 -2
- package/dist/esm/payments/hobex-hps/connect-client.d.ts +104 -0
- package/dist/esm/payments/hobex-hps/connect-client.js +156 -0
- package/dist/esm/payments/hobex-hps/errors.d.ts +122 -0
- package/dist/esm/payments/hobex-hps/errors.js +149 -0
- package/dist/esm/payments/hobex-hps/events.d.ts +22 -0
- package/dist/esm/payments/hobex-hps/events.js +1 -0
- package/dist/esm/payments/hobex-hps/index.d.ts +27 -0
- package/dist/esm/payments/hobex-hps/index.js +26 -0
- package/dist/esm/payments/hobex-hps/outcome.d.ts +31 -0
- package/dist/esm/payments/hobex-hps/outcome.js +4 -0
- package/dist/esm/payments/hobex-hps/payments.d.ts +149 -0
- package/dist/esm/payments/hobex-hps/payments.js +547 -0
- package/dist/esm/payments/hobex-hps/receipt.d.ts +28 -0
- package/dist/esm/payments/hobex-hps/receipt.js +57 -0
- package/dist/esm/payments/hobex-hps/transaction-id.d.ts +65 -0
- package/dist/esm/payments/hobex-hps/transaction-id.js +86 -0
- package/dist/esm/payments/hobex-hps/transaction-response.d.ts +163 -0
- package/dist/esm/payments/hobex-hps/transaction-response.js +233 -0
- package/dist/esm/payments/hobex.js +9 -6
- package/dist/esm/payments/index.d.ts +26 -14
- package/dist/esm/payments/index.js +26 -14
- package/dist/esm/printing/index.d.ts +1 -1
- package/dist/esm/printing/index.js +1 -1
- package/dist/esm/printing/webusb.d.ts +37 -7
- package/dist/esm/printing/webusb.js +74 -17
- package/dist/esm/receipt/epos.d.ts +18 -0
- package/dist/esm/receipt/epos.js +76 -6
- package/dist/esm/receipt/index.d.ts +1 -1
- package/dist/esm/receipt/index.js +1 -1
- package/dist/esm/register/index.d.ts +1 -1
- package/dist/esm/register/index.js +1 -1
- package/dist/esm/register/pairing.d.ts +67 -1
- package/dist/esm/register/pairing.js +58 -3
- package/fixtures/hobex-hps-codes.json +67 -0
- package/fixtures/oberflaeche.json +3 -1
- package/package.json +4 -2
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Erzeugung und Pruefung der HPS-Transaktionskennung.
|
|
3
|
+
*
|
|
4
|
+
* **Die Kennung steht VOR dem ersten Netzweg fest.** Kasseneck Connects
|
|
5
|
+
* eigene Doku sagt es woertlich: "`transactionId` MUSS die Kasse vergeben und
|
|
6
|
+
* sich merken" (`kasseneck-connect/lib/src/api/routes_terminal.dart`,
|
|
7
|
+
* `_handlePayment`). Ohne das ist ein abgerissener Vorgang unauffindbar — das
|
|
8
|
+
* ist der Kernfehler vom 24.08.2026.
|
|
9
|
+
*
|
|
10
|
+
* **Warum nicht `newHobexTransactionId` aus `../hobex.js`?** Diese Funktion
|
|
11
|
+
* erzeugt 19 Ziffern (Zeitanteil + Zufall) fuer die Hobex-CLOUD-API, die keine
|
|
12
|
+
* Laengengrenze dokumentiert. Das HPS-REST-Terminal dagegen erlaubt
|
|
13
|
+
* hoechstens **18** Ziffern (`kasseneck-connect`s eigene Pruefung,
|
|
14
|
+
* `_transactionId`-Regex in `routes_terminal.dart`, und `HpsClient`s
|
|
15
|
+
* `_maxTransactionIdLength` im Dart-Zwilling) — eine 19-stellige Kennung waere
|
|
16
|
+
* an dieser Schnittstelle bereits eine Formverletzung, VOR jeder Pruefung auf
|
|
17
|
+
* "rein numerisch". Sie taugt hier also nicht.
|
|
18
|
+
*
|
|
19
|
+
* Stattdessen **derselbe Ansatz wie `HpsClient.newTransactionId()`** im
|
|
20
|
+
* Dart-Zwilling: Millisekunden-Zeitstempel (13 Ziffern) plus ein 5-stelliger
|
|
21
|
+
* Zaehler je Millisekunde, macht genau 18 Ziffern. Der Zeitstempel beginnt
|
|
22
|
+
* bis zum Jahr 2286 nicht mit einer Null — das schliesst die Falle, vor der
|
|
23
|
+
* gewarnt wurde ("fuehrende Nullen werden am Terminal normalisiert, zwei
|
|
24
|
+
* Kennungen waeren sonst derselbe Vorgang"): zwei in dieser Millisekunde
|
|
25
|
+
* erzeugte Kennungen unterscheiden sich immer im Zaehler-Suffix, nie nur in
|
|
26
|
+
* einer fuehrenden Null.
|
|
27
|
+
*/
|
|
28
|
+
/** Laengengrenze der Kennung laut HPS-REST-Spezifikation (siehe oben). */
|
|
29
|
+
export declare const MAX_TRANSACTION_ID_LENGTH = 18;
|
|
30
|
+
/**
|
|
31
|
+
* `true`, wenn [value] als HPS-Transaktionskennung taugt: nicht leer,
|
|
32
|
+
* hoechstens [MAX_TRANSACTION_ID_LENGTH] Zeichen, rein numerisch.
|
|
33
|
+
*
|
|
34
|
+
* Bewusst KEINE Pruefung auf eine fuehrende Null bei einer selbst
|
|
35
|
+
* UEBERGEBENEN Kennung — weder Connects Formregel noch der Dart-Zwilling
|
|
36
|
+
* verlangen das von einem Aufrufer, der eine eigene Kennung mitbringt (siehe
|
|
37
|
+
* `HpsClient._checkTransactionId`). Die Falle betrifft nur die ERZEUGUNG,
|
|
38
|
+
* siehe [newHpsTransactionId].
|
|
39
|
+
*/
|
|
40
|
+
export declare function isValidHpsTransactionId(value: string): boolean;
|
|
41
|
+
export interface HpsTransactionIdGeneratorOptions {
|
|
42
|
+
/** Uhr fuer die Kennung; Vorgabe `Date.now`. Einspeisbar fuer Tests. */
|
|
43
|
+
now?: () => number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Erzeugt eine Funktion, die bei jedem Aufruf eine neue, innerhalb dieses
|
|
47
|
+
* Erzeugers eindeutige Kennung liefert.
|
|
48
|
+
*
|
|
49
|
+
* Eindeutigkeit ist eine LOGISCHE Uhr, angelehnt an das Snowflake-Verfahren:
|
|
50
|
+
* die zuletzt vergebene Millisekunde laeuft niemals rueckwaerts. Liefert die
|
|
51
|
+
* Uhr keinen groesseren Wert als beim letzten Aufruf — egal ob dieselbe
|
|
52
|
+
* Millisekunde oder eine zurueckspringende Uhr (Zeitumstellung,
|
|
53
|
+
* NTP-Korrektur) — bleibt die Millisekunde stehen und nur der Zaehler steigt.
|
|
54
|
+
* Ist der Zaehler einer Millisekunde ausgeschoepft (100000 Kennungen),
|
|
55
|
+
* schaltet die Millisekunde gedanklich um eins weiter.
|
|
56
|
+
*
|
|
57
|
+
* Die Garantie gilt nur INNERHALB des einen Erzeugers (eigener, gekapselter
|
|
58
|
+
* Zustand) — zwei getrennte Erzeuger oder Prozesse, die in derselben
|
|
59
|
+
* Millisekunde eine Kennung bilden, koennen kollidieren. Fuer den Einsatz
|
|
60
|
+
* hier passt das: eine Kasse erzeugt Kennungen aus genau einem laufenden
|
|
61
|
+
* Prozess.
|
|
62
|
+
*/
|
|
63
|
+
export declare function createHpsTransactionIdGenerator(options?: HpsTransactionIdGeneratorOptions): () => string;
|
|
64
|
+
/** Bequeme Vorgabeinstanz fuer den Alltagsgebrauch — eigener, gekapselter Zustand. */
|
|
65
|
+
export declare const newHpsTransactionId: () => string;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Erzeugung und Pruefung der HPS-Transaktionskennung.
|
|
4
|
+
*
|
|
5
|
+
* **Die Kennung steht VOR dem ersten Netzweg fest.** Kasseneck Connects
|
|
6
|
+
* eigene Doku sagt es woertlich: "`transactionId` MUSS die Kasse vergeben und
|
|
7
|
+
* sich merken" (`kasseneck-connect/lib/src/api/routes_terminal.dart`,
|
|
8
|
+
* `_handlePayment`). Ohne das ist ein abgerissener Vorgang unauffindbar — das
|
|
9
|
+
* ist der Kernfehler vom 24.08.2026.
|
|
10
|
+
*
|
|
11
|
+
* **Warum nicht `newHobexTransactionId` aus `../hobex.js`?** Diese Funktion
|
|
12
|
+
* erzeugt 19 Ziffern (Zeitanteil + Zufall) fuer die Hobex-CLOUD-API, die keine
|
|
13
|
+
* Laengengrenze dokumentiert. Das HPS-REST-Terminal dagegen erlaubt
|
|
14
|
+
* hoechstens **18** Ziffern (`kasseneck-connect`s eigene Pruefung,
|
|
15
|
+
* `_transactionId`-Regex in `routes_terminal.dart`, und `HpsClient`s
|
|
16
|
+
* `_maxTransactionIdLength` im Dart-Zwilling) — eine 19-stellige Kennung waere
|
|
17
|
+
* an dieser Schnittstelle bereits eine Formverletzung, VOR jeder Pruefung auf
|
|
18
|
+
* "rein numerisch". Sie taugt hier also nicht.
|
|
19
|
+
*
|
|
20
|
+
* Stattdessen **derselbe Ansatz wie `HpsClient.newTransactionId()`** im
|
|
21
|
+
* Dart-Zwilling: Millisekunden-Zeitstempel (13 Ziffern) plus ein 5-stelliger
|
|
22
|
+
* Zaehler je Millisekunde, macht genau 18 Ziffern. Der Zeitstempel beginnt
|
|
23
|
+
* bis zum Jahr 2286 nicht mit einer Null — das schliesst die Falle, vor der
|
|
24
|
+
* gewarnt wurde ("fuehrende Nullen werden am Terminal normalisiert, zwei
|
|
25
|
+
* Kennungen waeren sonst derselbe Vorgang"): zwei in dieser Millisekunde
|
|
26
|
+
* erzeugte Kennungen unterscheiden sich immer im Zaehler-Suffix, nie nur in
|
|
27
|
+
* einer fuehrenden Null.
|
|
28
|
+
*/
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.newHpsTransactionId = exports.MAX_TRANSACTION_ID_LENGTH = void 0;
|
|
31
|
+
exports.isValidHpsTransactionId = isValidHpsTransactionId;
|
|
32
|
+
exports.createHpsTransactionIdGenerator = createHpsTransactionIdGenerator;
|
|
33
|
+
/** Laengengrenze der Kennung laut HPS-REST-Spezifikation (siehe oben). */
|
|
34
|
+
exports.MAX_TRANSACTION_ID_LENGTH = 18;
|
|
35
|
+
const NUMERIC_TRANSACTION_ID = /^\d+$/;
|
|
36
|
+
/**
|
|
37
|
+
* `true`, wenn [value] als HPS-Transaktionskennung taugt: nicht leer,
|
|
38
|
+
* hoechstens [MAX_TRANSACTION_ID_LENGTH] Zeichen, rein numerisch.
|
|
39
|
+
*
|
|
40
|
+
* Bewusst KEINE Pruefung auf eine fuehrende Null bei einer selbst
|
|
41
|
+
* UEBERGEBENEN Kennung — weder Connects Formregel noch der Dart-Zwilling
|
|
42
|
+
* verlangen das von einem Aufrufer, der eine eigene Kennung mitbringt (siehe
|
|
43
|
+
* `HpsClient._checkTransactionId`). Die Falle betrifft nur die ERZEUGUNG,
|
|
44
|
+
* siehe [newHpsTransactionId].
|
|
45
|
+
*/
|
|
46
|
+
function isValidHpsTransactionId(value) {
|
|
47
|
+
return value.length > 0 && value.length <= exports.MAX_TRANSACTION_ID_LENGTH && NUMERIC_TRANSACTION_ID.test(value);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Erzeugt eine Funktion, die bei jedem Aufruf eine neue, innerhalb dieses
|
|
51
|
+
* Erzeugers eindeutige Kennung liefert.
|
|
52
|
+
*
|
|
53
|
+
* Eindeutigkeit ist eine LOGISCHE Uhr, angelehnt an das Snowflake-Verfahren:
|
|
54
|
+
* die zuletzt vergebene Millisekunde laeuft niemals rueckwaerts. Liefert die
|
|
55
|
+
* Uhr keinen groesseren Wert als beim letzten Aufruf — egal ob dieselbe
|
|
56
|
+
* Millisekunde oder eine zurueckspringende Uhr (Zeitumstellung,
|
|
57
|
+
* NTP-Korrektur) — bleibt die Millisekunde stehen und nur der Zaehler steigt.
|
|
58
|
+
* Ist der Zaehler einer Millisekunde ausgeschoepft (100000 Kennungen),
|
|
59
|
+
* schaltet die Millisekunde gedanklich um eins weiter.
|
|
60
|
+
*
|
|
61
|
+
* Die Garantie gilt nur INNERHALB des einen Erzeugers (eigener, gekapselter
|
|
62
|
+
* Zustand) — zwei getrennte Erzeuger oder Prozesse, die in derselben
|
|
63
|
+
* Millisekunde eine Kennung bilden, koennen kollidieren. Fuer den Einsatz
|
|
64
|
+
* hier passt das: eine Kasse erzeugt Kennungen aus genau einem laufenden
|
|
65
|
+
* Prozess.
|
|
66
|
+
*/
|
|
67
|
+
function createHpsTransactionIdGenerator(options = {}) {
|
|
68
|
+
const now = options.now ?? Date.now;
|
|
69
|
+
let lastMs = null;
|
|
70
|
+
let counter = 0;
|
|
71
|
+
return function newHpsTransactionId() {
|
|
72
|
+
const current = Math.trunc(now());
|
|
73
|
+
let ms;
|
|
74
|
+
if (lastMs === null || current > lastMs) {
|
|
75
|
+
ms = current;
|
|
76
|
+
counter = 0;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
ms = lastMs;
|
|
80
|
+
counter += 1;
|
|
81
|
+
if (counter >= 100_000) {
|
|
82
|
+
ms += 1;
|
|
83
|
+
counter = 0;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
lastMs = ms;
|
|
87
|
+
return `${ms}${String(counter).padStart(5, '0')}`;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/** Bequeme Vorgabeinstanz fuer den Alltagsgebrauch — eigener, gekapselter Zustand. */
|
|
91
|
+
exports.newHpsTransactionId = createHpsTransactionIdGenerator();
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antwort des hobex-HPS-Terminals auf eine Zahlung oder eine Statusabfrage,
|
|
3
|
+
* durchgereicht von **Kasseneck Connect** (`POST /v1/terminal/payment`,
|
|
4
|
+
* `/status`, `/abort` — Feld `hps` im Erfolgsrumpf). Connect ordnet nichts
|
|
5
|
+
* ein, es reicht den Terminal-Rumpf roh durch — die Einordnung passiert hier.
|
|
6
|
+
*
|
|
7
|
+
* **Zwilling:** `kasseneck_api/lib/src/hobex_hps/transaction_response.dart`.
|
|
8
|
+
* Beide Seiten pinnen dieselbe Codetabelle, siehe `HPS_MEASURED_CODES` unten
|
|
9
|
+
* und `fixtures/hobex-hps-codes.json`.
|
|
10
|
+
*
|
|
11
|
+
* **`responseCode !== '0'` ist NICHT die Pruefung auf eine Ablehnung.** Genau
|
|
12
|
+
* diese Lesart hat am 24.08.2026 zur doppelten Belastung gefuehrt:
|
|
13
|
+
* [NO_STATEMENT_CODE] (`9027`) ist ein Code ungleich `'0'` und sagt trotzdem
|
|
14
|
+
* nichts aus — er steht am gemessenen Terminal gleichermassen fuer "laeuft
|
|
15
|
+
* gerade", "abgebrochen" und "nie gesehen". Wer ihn als Ablehnung liest,
|
|
16
|
+
* meldet fuer einen LAUFENDEN Vorgang "nichts belastet, Wiederholung
|
|
17
|
+
* gefahrlos".
|
|
18
|
+
*
|
|
19
|
+
* [isConclusive] ist die einzige Stelle, an der ein Code zu einem Ausgang
|
|
20
|
+
* wird — und sie ist eine ECHTE Positivliste: nur ein Code, dessen Bedeutung
|
|
21
|
+
* GEMESSEN und in [HPS_MEASURED_CODES] benannt ist, zaehlt. Jeder andere —
|
|
22
|
+
* auch ein neuer, heute noch unbekannter Code — ist eine Wissensluecke, siehe
|
|
23
|
+
* [isUnknownCode]. Am 27.08.2026 hat der Dart-Zwilling gemessen, warum die
|
|
24
|
+
* Gegenrichtung ("jeder Code ausser 9027 ist schluessig") gefaehrlich ist: ein
|
|
25
|
+
* bis dahin unbenannter Code ([TECHNICAL_ERROR_CODE], `9900`) war darueber
|
|
26
|
+
* schluessig und haette eine Zahlung, unter der tatsaechlich Geld geflossen
|
|
27
|
+
* sein kann, als `declined` gemeldet.
|
|
28
|
+
*/
|
|
29
|
+
/** Ein Ergebniscode, dessen Bedeutung GEMESSEN und hier benannt ist. */
|
|
30
|
+
export interface HpsMeasuredCode {
|
|
31
|
+
/** Der Ergebniscode, wie ihn das Terminal im Feld `responseCode` sendet. */
|
|
32
|
+
readonly code: string;
|
|
33
|
+
/** Bedeutung, wie gemessen — deutsch, ohne Umlaute (siehe Vorbild). */
|
|
34
|
+
readonly meaning: string;
|
|
35
|
+
/**
|
|
36
|
+
* `true`: der Code schreibt einen Ausgang fest (Teil der Positivliste,
|
|
37
|
+
* siehe [isConclusive]). `false`: gemessen und benannt, aber ausdruecklich
|
|
38
|
+
* KEINE Aussage ueber den Vorgang (9027, 9900).
|
|
39
|
+
*/
|
|
40
|
+
readonly conclusive: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Die gemessene Codetabelle — Vertrag mit dem Dart-Zwilling, siehe
|
|
44
|
+
* `fixtures/hobex-hps-codes.json`. Gemessen an einem hobex-HPS (TID 3600335,
|
|
45
|
+
* HPS 1.10.0, Firmware 7.3.6, 26.–28.08.2026).
|
|
46
|
+
*
|
|
47
|
+
* Reihenfolge ist die im Messprotokoll (`doc/kartenzahlung.md` im
|
|
48
|
+
* Dart-Zwilling) — numerisch aufsteigend zu sortieren wuerde beim Diff
|
|
49
|
+
* gegen die Vertragsdatei nichts gewinnen und macht Aenderungen schwerer
|
|
50
|
+
* nachzuverfolgen.
|
|
51
|
+
*/
|
|
52
|
+
export declare const HPS_MEASURED_CODES: readonly HpsMeasuredCode[];
|
|
53
|
+
/** `responseCode` einer genehmigten Zahlung. */
|
|
54
|
+
export declare const APPROVED_CODE = "0";
|
|
55
|
+
/** Siehe [HPS_MEASURED_CODES]: ungueltiger Vorgang, nichts passiert. */
|
|
56
|
+
export declare const INVALID_TRANSACTION_CODE = "9002";
|
|
57
|
+
/** Siehe [HPS_MEASURED_CODES]: aufgehoben. */
|
|
58
|
+
export declare const TRANSACTION_CANCELED_CODE = "9011";
|
|
59
|
+
/** Siehe [HPS_MEASURED_CODES]: keine Aussage. */
|
|
60
|
+
export declare const NO_STATEMENT_CODE = "9027";
|
|
61
|
+
/** Siehe [HPS_MEASURED_CODES]: Kennung nicht numerisch, keine Aussage. */
|
|
62
|
+
export declare const TECHNICAL_ERROR_CODE = "9900";
|
|
63
|
+
/** Siehe [HPS_MEASURED_CODES]: abgebrochen. */
|
|
64
|
+
export declare const ABORTED_CODE = "100002";
|
|
65
|
+
/** Siehe [HPS_MEASURED_CODES]: Karte nicht aufgelegt. */
|
|
66
|
+
export declare const CARD_NOT_PRESENT_CODE = "100003";
|
|
67
|
+
/** Siehe [HPS_MEASURED_CODES]: nicht mehr abbrechbar. */
|
|
68
|
+
export declare const NOT_ABORTABLE_CODE = "100010";
|
|
69
|
+
/** Siehe [HPS_MEASURED_CODES]: Betrag abgewiesen, vor dem Kartenfluss. */
|
|
70
|
+
export declare const INVALID_AMOUNT_CODE = "9003";
|
|
71
|
+
/** Siehe [HPS_MEASURED_CODES]: Betrag ausserhalb des zulaessigen Bereichs. */
|
|
72
|
+
export declare const AMOUNT_OUT_OF_RANGE_CODE = "100019";
|
|
73
|
+
/** Siehe [HPS_MEASURED_CODES]: Terminal-Kennung unbekannt. */
|
|
74
|
+
export declare const INVALID_TID_CODE = "100108";
|
|
75
|
+
/**
|
|
76
|
+
* HTTP `409` ("Terminal is busy"): das Terminal serialisiert und weist eine
|
|
77
|
+
* zweite Anfrage ab, waehrend eine erste noch laeuft. Am 27.08.2026 gemessen:
|
|
78
|
+
* kommt nach 87 Millisekunden, der abgewiesene Vorgang hinterlaesst KEINE
|
|
79
|
+
* Spur (die Statusabfrage auf seine Kennung liefert weiterhin
|
|
80
|
+
* [NO_STATEMENT_CODE]).
|
|
81
|
+
*
|
|
82
|
+
* Bewusst KEIN Eintrag in [HPS_MEASURED_CODES]: es ist ein HTTP-Status, kein
|
|
83
|
+
* `responseCode` — er entsteht, bevor ueberhaupt ein Antwortrumpf gelesen
|
|
84
|
+
* wird. Siehe `errors.ts` (`HpsConnectTerminalError.isTerminalBusy`) fuer die
|
|
85
|
+
* getrennte Auswertung.
|
|
86
|
+
*/
|
|
87
|
+
export declare const TERMINAL_BUSY_HTTP_STATUS = 409;
|
|
88
|
+
/** Antwort des Terminals — Zahlung, Statusabfrage oder Abbruch. */
|
|
89
|
+
export interface HpsTransactionResponse {
|
|
90
|
+
/** Kennung dieser Transaktion, wie vom Terminal bestaetigt bzw. echoed. */
|
|
91
|
+
readonly transactionId: string | undefined;
|
|
92
|
+
/** Kennung der Original-Transaktion (Gutschrift, Aufhebung). */
|
|
93
|
+
readonly originalTransactionId: string | undefined;
|
|
94
|
+
readonly tid: string | undefined;
|
|
95
|
+
readonly receipt: string | undefined;
|
|
96
|
+
readonly approvalCode: string | undefined;
|
|
97
|
+
readonly reference: string | undefined;
|
|
98
|
+
readonly transactionDate: string | undefined;
|
|
99
|
+
readonly cardNumber: string | undefined;
|
|
100
|
+
readonly cardExpiry: string | undefined;
|
|
101
|
+
readonly brand: string | undefined;
|
|
102
|
+
readonly cardIssuer: string | undefined;
|
|
103
|
+
readonly transactionType: string | undefined;
|
|
104
|
+
readonly currency: string | undefined;
|
|
105
|
+
readonly amount: number | undefined;
|
|
106
|
+
readonly tip: number | undefined;
|
|
107
|
+
/**
|
|
108
|
+
* Ergebniscode. `undefined` (nur bei einer Statusabfrage moeglich) heisst
|
|
109
|
+
* "laeuft noch" — siehe [isInProgress]. Auf dieser Firmware ungemessen,
|
|
110
|
+
* bleibt aber ebenso eine Nicht-Aussage wie [NO_STATEMENT_CODE].
|
|
111
|
+
*
|
|
112
|
+
* Ein leerer String aus dem Rumpf wird beim Einlesen zu `undefined`
|
|
113
|
+
* normalisiert (siehe [parseHpsTransactionResponse]): er traegt keine
|
|
114
|
+
* Aussage, und `!== '0'` wuerde ihn sonst faelschlich als Ablehnung lesen.
|
|
115
|
+
*/
|
|
116
|
+
readonly responseCode: string | undefined;
|
|
117
|
+
readonly responseText: string | undefined;
|
|
118
|
+
/** Nur Statusabfrage (v2). Auf der gemessenen Firmware durchgehend `undefined`. */
|
|
119
|
+
readonly state: string | undefined;
|
|
120
|
+
/** Der roh decodierte Rumpf, fuer Felder ohne eigenes Modell. */
|
|
121
|
+
readonly raw: Record<string, unknown>;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Liest eine Terminal-Antwort aus dem `hps`-Feld der Connect-Huelle.
|
|
125
|
+
*
|
|
126
|
+
* Wirft, wenn [raw] keine brauchbare Form hat (kein Objekt) — das ist ein
|
|
127
|
+
* Formfehler der Antwort, kein Ausgang der Zahlung, und wird vom Aufrufer
|
|
128
|
+
* (`payments.ts`) genauso behandelt wie jeder andere unerwartete Fehler: die
|
|
129
|
+
* Klaerung laeuft konservativ weiter, statt ihn stillschweigend als
|
|
130
|
+
* "laeuft noch" zu deuten.
|
|
131
|
+
*/
|
|
132
|
+
export declare function parseHpsTransactionResponse(raw: unknown): HpsTransactionResponse;
|
|
133
|
+
/** `true`, wenn der Vorgang genehmigt ist. */
|
|
134
|
+
export declare function isApproved(res: Pick<HpsTransactionResponse, 'responseCode'>): boolean;
|
|
135
|
+
/** `true`, wenn eine Statusabfrage meldet, der Vorgang laeuft noch (kein Code). */
|
|
136
|
+
export declare function isInProgress(res: Pick<HpsTransactionResponse, 'responseCode'>): boolean;
|
|
137
|
+
/** `true`, wenn ein Abbruch daran scheiterte, dass der Vorgang nicht mehr abbrechbar war. */
|
|
138
|
+
export declare function isNotAbortable(res: Pick<HpsTransactionResponse, 'responseCode'>): boolean;
|
|
139
|
+
/** `true`, wenn das Terminal zu dieser Kennung keine Auskunft gibt (9027). */
|
|
140
|
+
export declare function isNoStatement(res: Pick<HpsTransactionResponse, 'responseCode'>): boolean;
|
|
141
|
+
/** `true`, wenn das Terminal einen technischen Fehler meldet (9900). */
|
|
142
|
+
export declare function isTechnicalError(res: Pick<HpsTransactionResponse, 'responseCode'>): boolean;
|
|
143
|
+
/**
|
|
144
|
+
* `true`, wenn der Vorgang unter dieser Kennung aufgehoben wurde (9011).
|
|
145
|
+
*
|
|
146
|
+
* Vorsicht bei der Verwendung: fuer die DIREKTE Antwort auf eine Aufhebung
|
|
147
|
+
* bedeutet dieser Code etwas anderes als bei einer Statusabfrage auf die
|
|
148
|
+
* Originalzahlung -- siehe `payments.ts`, `fromCancelResponse` vs.
|
|
149
|
+
* `fromCancelStatus`.
|
|
150
|
+
*/
|
|
151
|
+
export declare function isCanceled(res: Pick<HpsTransactionResponse, 'responseCode'>): boolean;
|
|
152
|
+
/**
|
|
153
|
+
* `true`, wenn diese Antwort ueberhaupt eine Aussage ueber den Ausgang
|
|
154
|
+
* traegt — ein Ergebniscode, der in [HPS_MEASURED_CODES] als `conclusive`
|
|
155
|
+
* gefuehrt wird. Die einzige Stelle, an der ein Code zu einem Ausgang wird.
|
|
156
|
+
*/
|
|
157
|
+
export declare function isConclusive(res: Pick<HpsTransactionResponse, 'responseCode'>): boolean;
|
|
158
|
+
/**
|
|
159
|
+
* `true`, wenn ein Ergebniscode VORHANDEN ist, aber weder schluessig noch
|
|
160
|
+
* eine der beiden gemessenen Wissensluecken ([isNoStatement],
|
|
161
|
+
* [isTechnicalError]) — ein Code, den dieses Modell schlicht nicht kennt.
|
|
162
|
+
*/
|
|
163
|
+
export declare function isUnknownCode(res: Pick<HpsTransactionResponse, 'responseCode'>): boolean;
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Antwort des hobex-HPS-Terminals auf eine Zahlung oder eine Statusabfrage,
|
|
4
|
+
* durchgereicht von **Kasseneck Connect** (`POST /v1/terminal/payment`,
|
|
5
|
+
* `/status`, `/abort` — Feld `hps` im Erfolgsrumpf). Connect ordnet nichts
|
|
6
|
+
* ein, es reicht den Terminal-Rumpf roh durch — die Einordnung passiert hier.
|
|
7
|
+
*
|
|
8
|
+
* **Zwilling:** `kasseneck_api/lib/src/hobex_hps/transaction_response.dart`.
|
|
9
|
+
* Beide Seiten pinnen dieselbe Codetabelle, siehe `HPS_MEASURED_CODES` unten
|
|
10
|
+
* und `fixtures/hobex-hps-codes.json`.
|
|
11
|
+
*
|
|
12
|
+
* **`responseCode !== '0'` ist NICHT die Pruefung auf eine Ablehnung.** Genau
|
|
13
|
+
* diese Lesart hat am 24.08.2026 zur doppelten Belastung gefuehrt:
|
|
14
|
+
* [NO_STATEMENT_CODE] (`9027`) ist ein Code ungleich `'0'` und sagt trotzdem
|
|
15
|
+
* nichts aus — er steht am gemessenen Terminal gleichermassen fuer "laeuft
|
|
16
|
+
* gerade", "abgebrochen" und "nie gesehen". Wer ihn als Ablehnung liest,
|
|
17
|
+
* meldet fuer einen LAUFENDEN Vorgang "nichts belastet, Wiederholung
|
|
18
|
+
* gefahrlos".
|
|
19
|
+
*
|
|
20
|
+
* [isConclusive] ist die einzige Stelle, an der ein Code zu einem Ausgang
|
|
21
|
+
* wird — und sie ist eine ECHTE Positivliste: nur ein Code, dessen Bedeutung
|
|
22
|
+
* GEMESSEN und in [HPS_MEASURED_CODES] benannt ist, zaehlt. Jeder andere —
|
|
23
|
+
* auch ein neuer, heute noch unbekannter Code — ist eine Wissensluecke, siehe
|
|
24
|
+
* [isUnknownCode]. Am 27.08.2026 hat der Dart-Zwilling gemessen, warum die
|
|
25
|
+
* Gegenrichtung ("jeder Code ausser 9027 ist schluessig") gefaehrlich ist: ein
|
|
26
|
+
* bis dahin unbenannter Code ([TECHNICAL_ERROR_CODE], `9900`) war darueber
|
|
27
|
+
* schluessig und haette eine Zahlung, unter der tatsaechlich Geld geflossen
|
|
28
|
+
* sein kann, als `declined` gemeldet.
|
|
29
|
+
*/
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
exports.TERMINAL_BUSY_HTTP_STATUS = exports.INVALID_TID_CODE = exports.AMOUNT_OUT_OF_RANGE_CODE = exports.INVALID_AMOUNT_CODE = exports.NOT_ABORTABLE_CODE = exports.CARD_NOT_PRESENT_CODE = exports.ABORTED_CODE = exports.TECHNICAL_ERROR_CODE = exports.NO_STATEMENT_CODE = exports.TRANSACTION_CANCELED_CODE = exports.INVALID_TRANSACTION_CODE = exports.APPROVED_CODE = exports.HPS_MEASURED_CODES = void 0;
|
|
32
|
+
exports.parseHpsTransactionResponse = parseHpsTransactionResponse;
|
|
33
|
+
exports.isApproved = isApproved;
|
|
34
|
+
exports.isInProgress = isInProgress;
|
|
35
|
+
exports.isNotAbortable = isNotAbortable;
|
|
36
|
+
exports.isNoStatement = isNoStatement;
|
|
37
|
+
exports.isTechnicalError = isTechnicalError;
|
|
38
|
+
exports.isCanceled = isCanceled;
|
|
39
|
+
exports.isConclusive = isConclusive;
|
|
40
|
+
exports.isUnknownCode = isUnknownCode;
|
|
41
|
+
/**
|
|
42
|
+
* Die gemessene Codetabelle — Vertrag mit dem Dart-Zwilling, siehe
|
|
43
|
+
* `fixtures/hobex-hps-codes.json`. Gemessen an einem hobex-HPS (TID 3600335,
|
|
44
|
+
* HPS 1.10.0, Firmware 7.3.6, 26.–28.08.2026).
|
|
45
|
+
*
|
|
46
|
+
* Reihenfolge ist die im Messprotokoll (`doc/kartenzahlung.md` im
|
|
47
|
+
* Dart-Zwilling) — numerisch aufsteigend zu sortieren wuerde beim Diff
|
|
48
|
+
* gegen die Vertragsdatei nichts gewinnen und macht Aenderungen schwerer
|
|
49
|
+
* nachzuverfolgen.
|
|
50
|
+
*/
|
|
51
|
+
exports.HPS_MEASURED_CODES = [
|
|
52
|
+
{ code: '0', meaning: 'genehmigt', conclusive: true },
|
|
53
|
+
{
|
|
54
|
+
code: '9002',
|
|
55
|
+
meaning: 'ungueltiger Vorgang -- das Terminal hat den Vorgang selbst als '
|
|
56
|
+
+ 'unzulaessig verworfen, bevor irgendetwas in Bewegung kam',
|
|
57
|
+
conclusive: true,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
code: '9011',
|
|
61
|
+
meaning: "aufgehoben (\"Transaction Canceled\") -- der Vorgang unter dieser Kennung wurde storniert",
|
|
62
|
+
conclusive: true,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
code: '9027',
|
|
66
|
+
meaning: 'keine Aussage -- steht gleichermassen fuer "nie gesehen", '
|
|
67
|
+
+ '"laeuft gerade", "Karte nicht aufgelegt" und "abgebrochen"',
|
|
68
|
+
conclusive: false,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
code: '9900',
|
|
72
|
+
meaning: '"Technical Error Database" -- gemessen im Zusammenhang mit '
|
|
73
|
+
+ 'einer nicht rein numerischen Kennung; keine Aussage ueber den Vorgang selbst',
|
|
74
|
+
conclusive: false,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
code: '9003',
|
|
78
|
+
meaning: '"Invalid Amount" -- der Betrag wird abgewiesen, BEVOR eine Karte '
|
|
79
|
+
+ 'verlangt wird (28.08.2026: 99999,99 EUR, Antwort nach 15,7 s ohne '
|
|
80
|
+
+ 'Kartenaufforderung); nichts belastet',
|
|
81
|
+
conclusive: true,
|
|
82
|
+
},
|
|
83
|
+
{ code: '100002', meaning: 'abgebrochen ("Aborted")', conclusive: true },
|
|
84
|
+
{ code: '100003', meaning: 'Karte nicht aufgelegt ("Card not present")', conclusive: true },
|
|
85
|
+
{ code: '100010', meaning: 'nicht mehr abbrechbar -- der Vorgang ist bereits abgeschlossen', conclusive: true },
|
|
86
|
+
{
|
|
87
|
+
code: '100019',
|
|
88
|
+
meaning: '"Amount is not in a valid range" -- Betrag ausserhalb des '
|
|
89
|
+
+ 'zulaessigen Bereichs, gemessen mit negativem Betrag; Abweisung vor '
|
|
90
|
+
+ 'dem Kartenfluss, nichts belastet',
|
|
91
|
+
conclusive: true,
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
code: '100108',
|
|
95
|
+
meaning: '"Invalid TID" -- die Terminal-Kennung gibt es an diesem Geraet '
|
|
96
|
+
+ 'nicht; der Vorgang wird abgewiesen, bevor etwas geschieht',
|
|
97
|
+
conclusive: true,
|
|
98
|
+
},
|
|
99
|
+
];
|
|
100
|
+
/** `responseCode` einer genehmigten Zahlung. */
|
|
101
|
+
exports.APPROVED_CODE = '0';
|
|
102
|
+
/** Siehe [HPS_MEASURED_CODES]: ungueltiger Vorgang, nichts passiert. */
|
|
103
|
+
exports.INVALID_TRANSACTION_CODE = '9002';
|
|
104
|
+
/** Siehe [HPS_MEASURED_CODES]: aufgehoben. */
|
|
105
|
+
exports.TRANSACTION_CANCELED_CODE = '9011';
|
|
106
|
+
/** Siehe [HPS_MEASURED_CODES]: keine Aussage. */
|
|
107
|
+
exports.NO_STATEMENT_CODE = '9027';
|
|
108
|
+
/** Siehe [HPS_MEASURED_CODES]: Kennung nicht numerisch, keine Aussage. */
|
|
109
|
+
exports.TECHNICAL_ERROR_CODE = '9900';
|
|
110
|
+
/** Siehe [HPS_MEASURED_CODES]: abgebrochen. */
|
|
111
|
+
exports.ABORTED_CODE = '100002';
|
|
112
|
+
/** Siehe [HPS_MEASURED_CODES]: Karte nicht aufgelegt. */
|
|
113
|
+
exports.CARD_NOT_PRESENT_CODE = '100003';
|
|
114
|
+
/** Siehe [HPS_MEASURED_CODES]: nicht mehr abbrechbar. */
|
|
115
|
+
exports.NOT_ABORTABLE_CODE = '100010';
|
|
116
|
+
/** Siehe [HPS_MEASURED_CODES]: Betrag abgewiesen, vor dem Kartenfluss. */
|
|
117
|
+
exports.INVALID_AMOUNT_CODE = '9003';
|
|
118
|
+
/** Siehe [HPS_MEASURED_CODES]: Betrag ausserhalb des zulaessigen Bereichs. */
|
|
119
|
+
exports.AMOUNT_OUT_OF_RANGE_CODE = '100019';
|
|
120
|
+
/** Siehe [HPS_MEASURED_CODES]: Terminal-Kennung unbekannt. */
|
|
121
|
+
exports.INVALID_TID_CODE = '100108';
|
|
122
|
+
/**
|
|
123
|
+
* HTTP `409` ("Terminal is busy"): das Terminal serialisiert und weist eine
|
|
124
|
+
* zweite Anfrage ab, waehrend eine erste noch laeuft. Am 27.08.2026 gemessen:
|
|
125
|
+
* kommt nach 87 Millisekunden, der abgewiesene Vorgang hinterlaesst KEINE
|
|
126
|
+
* Spur (die Statusabfrage auf seine Kennung liefert weiterhin
|
|
127
|
+
* [NO_STATEMENT_CODE]).
|
|
128
|
+
*
|
|
129
|
+
* Bewusst KEIN Eintrag in [HPS_MEASURED_CODES]: es ist ein HTTP-Status, kein
|
|
130
|
+
* `responseCode` — er entsteht, bevor ueberhaupt ein Antwortrumpf gelesen
|
|
131
|
+
* wird. Siehe `errors.ts` (`HpsConnectTerminalError.isTerminalBusy`) fuer die
|
|
132
|
+
* getrennte Auswertung.
|
|
133
|
+
*/
|
|
134
|
+
exports.TERMINAL_BUSY_HTTP_STATUS = 409;
|
|
135
|
+
const KNOWN_OUTCOME_CODES = new Set(exports.HPS_MEASURED_CODES.filter((c) => c.conclusive).map((c) => c.code));
|
|
136
|
+
/**
|
|
137
|
+
* Liest eine Terminal-Antwort aus dem `hps`-Feld der Connect-Huelle.
|
|
138
|
+
*
|
|
139
|
+
* Wirft, wenn [raw] keine brauchbare Form hat (kein Objekt) — das ist ein
|
|
140
|
+
* Formfehler der Antwort, kein Ausgang der Zahlung, und wird vom Aufrufer
|
|
141
|
+
* (`payments.ts`) genauso behandelt wie jeder andere unerwartete Fehler: die
|
|
142
|
+
* Klaerung laeuft konservativ weiter, statt ihn stillschweigend als
|
|
143
|
+
* "laeuft noch" zu deuten.
|
|
144
|
+
*/
|
|
145
|
+
function parseHpsTransactionResponse(raw) {
|
|
146
|
+
if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
147
|
+
throw new TypeError('Terminal-Antwort ist kein JSON-Objekt');
|
|
148
|
+
}
|
|
149
|
+
const r = raw;
|
|
150
|
+
return {
|
|
151
|
+
transactionId: asString(r['transactionId']),
|
|
152
|
+
originalTransactionId: asString(r['originalTransactionId']),
|
|
153
|
+
tid: asString(r['tid']),
|
|
154
|
+
receipt: asString(r['receipt']),
|
|
155
|
+
approvalCode: asString(r['approvalCode']),
|
|
156
|
+
reference: asString(r['reference']),
|
|
157
|
+
transactionDate: asString(r['transactionDate']),
|
|
158
|
+
cardNumber: asString(r['cardNumber']),
|
|
159
|
+
cardExpiry: asString(r['cardExpiry']),
|
|
160
|
+
brand: asString(r['brand']),
|
|
161
|
+
cardIssuer: asString(r['cardIssuer']),
|
|
162
|
+
transactionType: asString(r['transactionType']),
|
|
163
|
+
currency: asString(r['currency']),
|
|
164
|
+
amount: asNumber(r['amount']),
|
|
165
|
+
tip: asNumber(r['tip']),
|
|
166
|
+
// responseCode kommt teils als Zahl, teils als Zeichenkette — siehe
|
|
167
|
+
// Zwilling. Ein leerer String traegt keine Aussage und wird wie ein
|
|
168
|
+
// fehlendes Feld behandelt.
|
|
169
|
+
responseCode: nonEmpty(stringify(r['responseCode'])),
|
|
170
|
+
responseText: asString(r['responseText']),
|
|
171
|
+
state: asString(r['state']),
|
|
172
|
+
raw: r,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function asString(v) {
|
|
176
|
+
return typeof v === 'string' ? v : undefined;
|
|
177
|
+
}
|
|
178
|
+
function asNumber(v) {
|
|
179
|
+
if (typeof v === 'number' && Number.isFinite(v))
|
|
180
|
+
return v;
|
|
181
|
+
if (typeof v === 'string' && v.trim() !== '') {
|
|
182
|
+
const n = Number(v);
|
|
183
|
+
return Number.isFinite(n) ? n : undefined;
|
|
184
|
+
}
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
function stringify(v) {
|
|
188
|
+
if (v === null || v === undefined)
|
|
189
|
+
return undefined;
|
|
190
|
+
if (typeof v === 'string')
|
|
191
|
+
return v;
|
|
192
|
+
if (typeof v === 'number')
|
|
193
|
+
return String(v);
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
function nonEmpty(v) {
|
|
197
|
+
return v === undefined || v === '' ? undefined : v;
|
|
198
|
+
}
|
|
199
|
+
/** `true`, wenn der Vorgang genehmigt ist. */
|
|
200
|
+
function isApproved(res) {
|
|
201
|
+
return res.responseCode === exports.APPROVED_CODE;
|
|
202
|
+
}
|
|
203
|
+
/** `true`, wenn eine Statusabfrage meldet, der Vorgang laeuft noch (kein Code). */
|
|
204
|
+
function isInProgress(res) {
|
|
205
|
+
return res.responseCode === undefined;
|
|
206
|
+
}
|
|
207
|
+
/** `true`, wenn ein Abbruch daran scheiterte, dass der Vorgang nicht mehr abbrechbar war. */
|
|
208
|
+
function isNotAbortable(res) {
|
|
209
|
+
return res.responseCode === exports.NOT_ABORTABLE_CODE;
|
|
210
|
+
}
|
|
211
|
+
/** `true`, wenn das Terminal zu dieser Kennung keine Auskunft gibt (9027). */
|
|
212
|
+
function isNoStatement(res) {
|
|
213
|
+
return res.responseCode === exports.NO_STATEMENT_CODE;
|
|
214
|
+
}
|
|
215
|
+
/** `true`, wenn das Terminal einen technischen Fehler meldet (9900). */
|
|
216
|
+
function isTechnicalError(res) {
|
|
217
|
+
return res.responseCode === exports.TECHNICAL_ERROR_CODE;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* `true`, wenn der Vorgang unter dieser Kennung aufgehoben wurde (9011).
|
|
221
|
+
*
|
|
222
|
+
* Vorsicht bei der Verwendung: fuer die DIREKTE Antwort auf eine Aufhebung
|
|
223
|
+
* bedeutet dieser Code etwas anderes als bei einer Statusabfrage auf die
|
|
224
|
+
* Originalzahlung -- siehe `payments.ts`, `fromCancelResponse` vs.
|
|
225
|
+
* `fromCancelStatus`.
|
|
226
|
+
*/
|
|
227
|
+
function isCanceled(res) {
|
|
228
|
+
return res.responseCode === exports.TRANSACTION_CANCELED_CODE;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* `true`, wenn diese Antwort ueberhaupt eine Aussage ueber den Ausgang
|
|
232
|
+
* traegt — ein Ergebniscode, der in [HPS_MEASURED_CODES] als `conclusive`
|
|
233
|
+
* gefuehrt wird. Die einzige Stelle, an der ein Code zu einem Ausgang wird.
|
|
234
|
+
*/
|
|
235
|
+
function isConclusive(res) {
|
|
236
|
+
return res.responseCode !== undefined && KNOWN_OUTCOME_CODES.has(res.responseCode);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* `true`, wenn ein Ergebniscode VORHANDEN ist, aber weder schluessig noch
|
|
240
|
+
* eine der beiden gemessenen Wissensluecken ([isNoStatement],
|
|
241
|
+
* [isTechnicalError]) — ein Code, den dieses Modell schlicht nicht kennt.
|
|
242
|
+
*/
|
|
243
|
+
function isUnknownCode(res) {
|
|
244
|
+
return res.responseCode !== undefined && !isConclusive(res) && !isNoStatement(res) && !isTechnicalError(res);
|
|
245
|
+
}
|
|
@@ -17,12 +17,15 @@ const money_js_1 = require("../money.js");
|
|
|
17
17
|
* functions/payment-endpoints.js) — sie ist deshalb kein Schmuck, sondern die
|
|
18
18
|
* Absicherung gegen eine doppelte Belastung.
|
|
19
19
|
*
|
|
20
|
-
* **Nur der Cloud-Weg ist hier drin
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
20
|
+
* **Nur der Cloud-Weg ist hier drin.** Hobex **HPS** ist ein physisches
|
|
21
|
+
* Terminal, mit dem eine Kasse **lokal ueber TCP** spricht — dafuer hat ein
|
|
22
|
+
* Browser weiterhin keine rohen Sockets. Anders als hier frueher vermerkt,
|
|
23
|
+
* heisst das aber NICHT mehr "unerreichbar ohne Flutter": `../hobex-hps.js`
|
|
24
|
+
* spricht mit dem Terminal ueber **Kasseneck Connect**, einen lokalen
|
|
25
|
+
* Geraete-Agenten mit gewoehnlicher HTTP-Schnittstelle. **myPOS** und
|
|
26
|
+
* **SumUp** bleiben Android-SDKs ohne Entsprechung hier. Wer am HPS-Terminal
|
|
27
|
+
* eine Gutschrift oder ein Storno braucht, braucht weiterhin die Flutter-App:
|
|
28
|
+
* Connect exponiert dafuer (noch) keinen Endpunkt.
|
|
26
29
|
*
|
|
27
30
|
* **Kassen-Benutzer-Weg (`registerUserAuth`, Browser-Kasse):** Keiner der
|
|
28
31
|
* beiden Endpunkte dieser Datei setzt `allowRegisterUser`; beide laufen nur
|
|
@@ -1,28 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Unterpfad `@kreiseck/kasseneck-api/payments` — die Zahlungswege, die ein
|
|
3
3
|
* Browser oder ein Node-Prozess wirklich gehen kann: **Stripe-Zahlungslinks**
|
|
4
|
-
* (Fernzahlung per Link/QR-Code)
|
|
5
|
-
* ueber ein bei Hobex registriertes Terminal, gesteuert ueber das Netz)
|
|
4
|
+
* (Fernzahlung per Link/QR-Code), die **Hobex-Cloud-API** (Kartenzahlung
|
|
5
|
+
* ueber ein bei Hobex registriertes Terminal, gesteuert ueber das Netz) und
|
|
6
|
+
* **Hobex HPS ueber Kasseneck Connect** (`./hobex-hps.js`) — ein physisches
|
|
7
|
+
* Terminal im Kassen-Netz, angesprochen ueber den lokalen Geraete-Agenten.
|
|
6
8
|
*
|
|
7
9
|
* **Was hier bewusst fehlt — und warum es auch nicht nachgeruestet wird:**
|
|
8
10
|
*
|
|
9
|
-
* - **Hobex HPS** spricht **lokal ueber TCP** mit einem angeschlossenen
|
|
10
|
-
* Terminal (roher Socket auf eine Geraete-IP im selben Netz).
|
|
11
11
|
* - **myPOS** und **SumUp** sind **Android-SDKs**; sie laufen als
|
|
12
12
|
* Bibliothek in einer Android-App und reden ueber Bluetooth bzw. das
|
|
13
|
-
* Hersteller-Geraet mit dem Terminal.
|
|
13
|
+
* Hersteller-Geraet mit dem Terminal. Ein Browser hat keine
|
|
14
|
+
* Android-Laufzeit — das ist keine Luecke in diesem Paket und auch nichts,
|
|
15
|
+
* was ein Buendler, ein Polyfill oder WebAssembly aufloest.
|
|
14
16
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* **Frueherer Stand, ueberholt:** hier stand einmal, Hobex HPS sei mangels
|
|
18
|
+
* roher TCP-Sockets im Browser unerreichbar. Das galt fuer den DIREKTEN
|
|
19
|
+
* Terminal-Kontakt (Zwilling: `HpsClient` in `kasseneck_api`) und gilt dafuer
|
|
20
|
+
* weiterhin — aber **Kasseneck Connect** ist ein lokaler Geraete-Agent, der
|
|
21
|
+
* ueber gewoehnliches HTTP erreichbar ist und **fuer** die Kasse mit dem
|
|
22
|
+
* Terminal spricht. Das ist kein Widerspruch zur Umgebungsgrenze, sondern ein
|
|
23
|
+
* zweiter, seit `hobex-hps.js` genutzter Weg um sie herum.
|
|
24
|
+
*
|
|
25
|
+
* Wer Gutschrift oder Storno am HPS-Terminal braucht, braucht weiterhin die
|
|
26
|
+
* Flutter-App: Connect exponiert dafuer (noch) keinen Endpunkt, siehe
|
|
27
|
+
* `hobex-hps/connect-client.ts`.
|
|
20
28
|
*
|
|
21
29
|
* **Kassen-Benutzer-Weg (`registerUserAuth`, Browser-Kasse):** **Keiner** der
|
|
22
|
-
* vier Zahlungs-Endpunkte setzt `allowRegisterUser`;
|
|
23
|
-
* `checkRequest(req, 'user', …)` und damit nur mit
|
|
24
|
-
* bildet das **nicht** nach — wer darf, entscheidet
|
|
25
|
-
* Hinweis steht **hier** und gilt fuer
|
|
30
|
+
* vier Cloud-Zahlungs-Endpunkte (Stripe, Hobex-Cloud) setzt `allowRegisterUser`;
|
|
31
|
+
* sie laufen alle ueber `checkRequest(req, 'user', …)` und damit nur mit
|
|
32
|
+
* `apiKeyAuth`. Dieses Paket bildet das **nicht** nach — wer darf, entscheidet
|
|
33
|
+
* allein das Backend. Der Hinweis steht **hier** und gilt fuer die beiden
|
|
34
|
+
* Cloud-Dateien dieses Unterpfads; `hobex-hps.js` spricht kein Kasseneck-Backend
|
|
35
|
+
* und kennt diese Unterscheidung nicht — dort entscheidet allein der
|
|
36
|
+
* Kopplungstoken von Kasseneck Connect.
|
|
26
37
|
*
|
|
27
38
|
* Welche **anderen** Endpunkte den Weg offen haben, steht bewusst nirgends in
|
|
28
39
|
* diesem Paket: eine abgeschriebene Liste veraltet still, und sie hat hier
|
|
@@ -31,3 +42,4 @@
|
|
|
31
42
|
export { StripeLinkMode, type StripeLinkModeKey } from '../enums/index.js';
|
|
32
43
|
export { type CreateStripeLinkOptions, type StripeCaptureResult, createStripeLink, stripeCaptureIntent, } from './stripe.js';
|
|
33
44
|
export { type HobexPayOptions, type HobexRefundOptions, type HobexTransactionIdOptions, hobexPay, hobexRefund, newHobexTransactionId, } from './hobex.js';
|
|
45
|
+
export { type CardPaymentOutcome, type HpsConnectClient, type HpsConnectClientOptions, type HpsConnectFetch, type HpsConnectFetchResponse, type HpsConnectPaymentOptions, type HpsConnectTarget, type HpsConnectTransactionOptions, type HpsMeasuredCode, type HpsPaymentEvent, type HpsPaymentEventKind, type HpsPaymentObserver, type HpsPaymentOptions, type HpsPayments, type HpsPaymentResult, type HpsPaymentsOptions, type HpsTransactionIdGeneratorOptions, type HpsTransactionResponse, ABORTED_CODE, APPROVED_CODE, CARD_NOT_PRESENT_CODE, createHpsConnectClient, createHpsPayments, createHpsTransactionIdGenerator, HPS_MEASURED_CODES, HpsClarifyTimeoutError, HpsConnectException, HpsConnectTerminalError, HpsConnectTransportError, HpsPreflightError, HpsTransactionIdError, INVALID_TRANSACTION_CODE, isApproved, isConclusive, isInProgress, isNoStatement, isNotAbortable, isTechnicalError, isUnknownCode, isValidHpsTransactionId, mayRetrySafely, MAX_TRANSACTION_ID_LENGTH, newHpsTransactionId, NOT_ABORTABLE_CODE, NO_STATEMENT_CODE, parseHpsTransactionResponse, PREFLIGHT_CONNECT_CODES, TECHNICAL_ERROR_CODE, TERMINAL_BUSY_HTTP_STATUS, TRANSACTION_CANCELED_CODE, } from './hobex-hps/index.js';
|