@kreiseck/kasseneck-api 0.9.4 → 0.11.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 +118 -0
- package/README.md +41 -0
- package/dist/cjs/payments/hobex-hps/index.d.ts +2 -2
- package/dist/cjs/payments/hobex-hps/index.js +36 -1
- package/dist/cjs/payments/hobex-hps/outcome.d.ts +20 -1
- package/dist/cjs/payments/hobex-hps/outcome.js +11 -0
- package/dist/cjs/payments/hobex-hps/payments.d.ts +19 -0
- package/dist/cjs/payments/hobex-hps/payments.js +160 -33
- package/dist/cjs/payments/hobex-hps/transaction-response.d.ts +180 -31
- package/dist/cjs/payments/hobex-hps/transaction-response.js +308 -88
- package/dist/cjs/payments/index.d.ts +1 -1
- package/dist/cjs/payments/index.js +8 -1
- package/dist/cjs/printing/escpos.d.ts +85 -1
- package/dist/cjs/printing/escpos.js +140 -4
- package/dist/cjs/printing/index.d.ts +2 -1
- package/dist/cjs/printing/index.js +13 -1
- package/dist/cjs/printing/qr-groesse.d.ts +122 -0
- package/dist/cjs/printing/qr-groesse.js +126 -0
- package/dist/cjs/receipt/epos.d.ts +42 -1
- package/dist/cjs/receipt/epos.js +66 -5
- package/dist/cjs/receipt/index.d.ts +2 -2
- package/dist/cjs/receipt/index.js +3 -1
- package/dist/cjs/receipt/layout-escpos.d.ts +50 -2
- package/dist/cjs/receipt/layout-escpos.js +59 -2
- package/dist/esm/payments/hobex-hps/index.d.ts +2 -2
- package/dist/esm/payments/hobex-hps/index.js +2 -2
- package/dist/esm/payments/hobex-hps/outcome.d.ts +20 -1
- package/dist/esm/payments/hobex-hps/outcome.js +10 -0
- package/dist/esm/payments/hobex-hps/payments.d.ts +19 -0
- package/dist/esm/payments/hobex-hps/payments.js +161 -34
- package/dist/esm/payments/hobex-hps/transaction-response.d.ts +180 -31
- package/dist/esm/payments/hobex-hps/transaction-response.js +302 -87
- package/dist/esm/payments/index.d.ts +1 -1
- package/dist/esm/payments/index.js +1 -1
- package/dist/esm/printing/escpos.d.ts +85 -1
- package/dist/esm/printing/escpos.js +138 -4
- package/dist/esm/printing/index.d.ts +2 -1
- package/dist/esm/printing/index.js +2 -1
- package/dist/esm/printing/qr-groesse.d.ts +122 -0
- package/dist/esm/printing/qr-groesse.js +120 -0
- package/dist/esm/receipt/epos.d.ts +42 -1
- package/dist/esm/receipt/epos.js +65 -5
- package/dist/esm/receipt/index.d.ts +2 -2
- package/dist/esm/receipt/index.js +2 -2
- package/dist/esm/receipt/layout-escpos.d.ts +50 -2
- package/dist/esm/receipt/layout-escpos.js +59 -3
- package/fixtures/hobex-hps-codes.json +365 -15
- package/fixtures/kasse-texte.json +1 -1
- package/fixtures/oberflaeche.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,124 @@ Was vor 0.7.0 geschah, steht in der Commit-Historie (`git log`); ab hier wird
|
|
|
4
4
|
es hier geführt. Ein Eintrag nennt die Änderung **und ihren Grund** —
|
|
5
5
|
nur der Grund überlebt den nächsten Umbau.
|
|
6
6
|
|
|
7
|
+
## 0.11.0
|
|
8
|
+
|
|
9
|
+
### Die QR-Modulgröße wird gerechnet, nicht gesetzt — samt Notausgang und Modell 1
|
|
10
|
+
|
|
11
|
+
**Anlass:** Am echten Beleg fehlte der QR-Code, die Probe im Drucker-Wizard
|
|
12
|
+
druckte ihn. Der native QR-Befehl bekommt eine Modulgröße in Druckpunkten mit
|
|
13
|
+
und rechnet nicht nach, ob das Symbol samt Ruhezone auf die Rolle geht. Ein
|
|
14
|
+
Beleg-QR mit realer RKSV-Nutzlast hat 57 Module, mit Ruhezone also 65; bei
|
|
15
|
+
sechs Punkten je Modul sind das 390 Druckpunkte, und ein 58-mm-Kopf hat 384.
|
|
16
|
+
Zu breit heißt bei den meisten Geräten nicht „abgeschnitten", sondern **gar
|
|
17
|
+
kein QR**. Der Befund stammt aus dem Flutter-Zwilling `kasseneck_api` (dort
|
|
18
|
+
6.9.0), der fest mit sechs Punkten druckte; dieses Paket druckt seit jeher mit
|
|
19
|
+
vier und war davon nicht betroffen. Die Regel ist trotzdem dieselbe — sie
|
|
20
|
+
deckelt auch eine bewusst gewählte größere Modulgröße gegen den Papierrand ab.
|
|
21
|
+
|
|
22
|
+
- **Neu `…/printing`: die Rechenregel, rein und ohne Drucker.**
|
|
23
|
+
`qrModulAnzahl(nutzlast)` gibt die Modulanzahl bei Fehlerkorrektur **M**
|
|
24
|
+
(konservativ: der native Befehl druckt mit L, das braucht nie mehr Module);
|
|
25
|
+
`qrGroesseBerechnen({ papierbreitePunkte, moduleAnzahl, groesse })` und
|
|
26
|
+
`qrGroesseFuer({ nutzlast, papierbreitePunkte, groesse })` geben ein
|
|
27
|
+
`QrGroesse` mit `punkte` (`null` = passt nicht), `module`, `breitePunkte`,
|
|
28
|
+
`unterMindestmass` und `passt`. Dazu `QrModulGroesse`, `QR_MODUL_DECKEL`,
|
|
29
|
+
`QR_RUHEZONE_MODULE` (4), `QR_MINDEST_PUNKTE` (4), `QR_AUSNAHME_PUNKTE` (3),
|
|
30
|
+
`QR_HOECHST_PUNKTE` (8) und `QR_DRUCK_PUNKTE` (58 mm = 384, 80 mm = 576 —
|
|
31
|
+
die echte Kopfbreite, nicht die Spaltenbreite 372/558).
|
|
32
|
+
- **`escPosQrCode` rechnet, wenn keine feste `size` mitkommt.** `groesse` ist
|
|
33
|
+
ein **Deckel**, keine Vorgabe: gedruckt wird die größte Größe, die noch
|
|
34
|
+
passt, höchstens aber der Deckel. `auto` deckelt beim Bestandswert dieses
|
|
35
|
+
Pakets (4), `klein` 4, `mittel` 6, `gross` 8. **Ohne ausdrückliche Wahl
|
|
36
|
+
ändert sich kein Byte** — nur dort, wo heute gar nichts herauskommt, rechnet
|
|
37
|
+
die Regel herunter. (Im Flutter-Zwilling deckelt `auto` bei 6, weil dort 6
|
|
38
|
+
der Bestandswert ist; die Regel ist dieselbe, der Bestand nicht.)
|
|
39
|
+
- **`EscPosDocument.qrFehler` / `.qrAusweich`.** `qrFehler` heißt „Beleg ohne
|
|
40
|
+
QR" — das Symbol passt auch mit der Ausnahmegröße nicht, und ein Befehl, von
|
|
41
|
+
dem man weiß, dass er nichts druckt, täuscht nur einen Ausdruck vor.
|
|
42
|
+
`qrAusweich` heißt „gedruckt, aber nicht auf dem eingestellten Weg" — unter
|
|
43
|
+
der Mindestgröße oder als Bild. Das eine gehört dem Kunden gesagt, das
|
|
44
|
+
andere dem Chef. `escPosReset` räumt beide weg.
|
|
45
|
+
- **Neu `…/receipt`: `escPosLayoutErgebnis`** gibt `{ bytes, qrFehler,
|
|
46
|
+
qrAusweich }`; `escPosLayoutBytes` bleibt unverändert und gibt weiter nur
|
|
47
|
+
die Bytes. Neue Optionen `qrGroesse`, `qrModus` (`QrPrintMode`) und
|
|
48
|
+
`qrMatrix`.
|
|
49
|
+
- **Der Notausgang.** Passt das Symbol nativ nicht aufs Papier und ist ein
|
|
50
|
+
`qrMatrix` mitgegeben, geht der QR als Rasterbild hinaus (`GS v 0`) statt
|
|
51
|
+
gar nicht — ein Pflichtbeleg ohne QR ist der schlechteste aller Ausgänge.
|
|
52
|
+
Das Raster kommt vom Aufrufer: dieses Paket rechnet keine QR-Codes und
|
|
53
|
+
verarbeitet keine Bilder. Dafür neu `escPosQrRaster`, `qrRasterPunkte` und
|
|
54
|
+
der Typ `QrMatrix`.
|
|
55
|
+
- **Modell 1.** `qrCodeBytes(..., { modell1: true })` bzw. `qrModus:
|
|
56
|
+
'nativeModel1'` stellt den Wahlbefehl `GS ( k 04 00 31 41 31 00` voran. Für
|
|
57
|
+
günstige Drucker, die nur diesen älteren Symboltyp beherrschen; belegt ist
|
|
58
|
+
eines, das bei Modell 2 unter dem Code eine „0" ausgibt — das Parameterbyte
|
|
59
|
+
`0x30` des Druckbefehls, das es nicht als Befehl erkennt. Ohne ausdrückliche
|
|
60
|
+
Wahl geht **gar kein** Modellbefehl hinaus, wie bisher.
|
|
61
|
+
- **Derselbe Fehler im ePOS-Weg — und dort ist er der akute.** `eposPrintXml`
|
|
62
|
+
setzte `<symbol … width="6">` fest, unabhängig von der Papierbreite: 57
|
|
63
|
+
Module plus Ruhezone sind bei sechs Punkten 390 Druckpunkte, ein 58-mm-Kopf
|
|
64
|
+
hat 384, und der Epson lässt ein zu breites Symbol weg. **Genau daran fehlte
|
|
65
|
+
am echten Beleg der QR.** Jetzt gilt dieselbe Regel — Untergrenze 4,
|
|
66
|
+
Ausnahme 3 mit Meldung, darunter kein `<symbol>`. Der Bestandswert dieses
|
|
67
|
+
Wegs ist 6, deshalb ist die Vorgabe hier der Deckel `mittel`; ohne
|
|
68
|
+
ausdrückliche Wahl ändert sich nur dort etwas, wo heute gar nichts
|
|
69
|
+
herauskommt. Neu `eposPrintXmlErgebnis` (`{ xml, qrFehler, qrAusweich }`) und
|
|
70
|
+
die Optionen `qrGroesse` an `eposPrintXml` und `eposDirectPrint`; `qrBreite`
|
|
71
|
+
bleibt, ist jetzt aber ausdrücklich die **feste** Größe und schaltet die
|
|
72
|
+
Rechnung ab.
|
|
73
|
+
- **Bestandsschutz als Golden-Test.** Zwei feste SHA-256 über den gesamten
|
|
74
|
+
Bytestrom eines Belegs (58 und 80 mm) und zwei weitere über das vollständige
|
|
75
|
+
ePOS-XML halten fest, dass sich ohne Wahl kein Byte ändert. Dazu prüft `test/paket-inhalt.test.ts`, dass die Dateiliste des
|
|
76
|
+
Pakets eine Positivliste bleibt und im mitgelieferten `fixtures/` nichts
|
|
77
|
+
Örtliches liegt.
|
|
78
|
+
|
|
79
|
+
## 0.10.0
|
|
80
|
+
|
|
81
|
+
### Die Antwortcodeliste von hobex — jeder Code eingeordnet, jeder Ausgang mit Grund
|
|
82
|
+
|
|
83
|
+
**Anlass:** hobex hat am 11.09.2026 die Antwortcodeliste der HPS-Anwendung
|
|
84
|
+
geschickt. Drei der Codes kamen seit dem 28.08.2026 im Betrieb vor (`100004`,
|
|
85
|
+
`100005`, `100015`) und waren bis jetzt ungedeutet. Jede Zahlung damit lief in
|
|
86
|
+
die Klaerung und endete erst ueber die Zwei-9027-Regel. Zwilling:
|
|
87
|
+
`kasseneck_api` 6.10.0 (6.9.0 war inzwischen vergeben), Begruendungen dort in
|
|
88
|
+
`doc/kartenzahlung.md`.
|
|
89
|
+
|
|
90
|
+
- **`HPS_CODES`** fuehrt alle 31 Codes der Liste zusammen mit den gemessenen:
|
|
91
|
+
Code, hobex-Titel, Bedeutung, Wirkung (`effect`), Grund (`reason`) und
|
|
92
|
+
Quelle (`source`). `isConclusive` liest seine Positivliste daraus.
|
|
93
|
+
`HPS_MEASURED_CODES` bleibt als abgekuendigter Name fuer dieselbe Tabelle.
|
|
94
|
+
- **Was vor dem Host scheitert, ist eine Ablehnung** (Kartenlesen, EMV-Kernel,
|
|
95
|
+
Eingaben am Geraet, Geraetezustand, fehlerhafte Anfrage) -- `declined`, ohne
|
|
96
|
+
Abbruch und ohne Statusabfrage. Dazu `100029`: das Terminal storniert laut
|
|
97
|
+
hobex selbst.
|
|
98
|
+
- **Neu: `effect: 'hostUncertain'`** (`isHostUncertain`) fuer `100006`,
|
|
99
|
+
`100007`, `100023`, `100024`, `100026`, `100027`, `100999`. Der Host war
|
|
100
|
+
beteiligt, das Terminal storniert nicht selbst. Die Zwei-9027-Regel greift
|
|
101
|
+
hier **nicht**; die Klaerung endet nach zwei Abfragen ohne Neues als
|
|
102
|
+
`unresolved`, nur ein `'0'` entscheidet danach noch, und ein Abbruchversuch
|
|
103
|
+
entfaellt. Bei einer Aufhebung entscheidet ein unveraendertes `'0'` auf die
|
|
104
|
+
Originalzahlung dann ebenfalls nichts.
|
|
105
|
+
- **`rejectsRequest` / `isConclusiveAsStatus`:** zehn Codes weisen die Anfrage
|
|
106
|
+
selbst ab (`9002`, `100001`, `100008`, `100108`, `100009`, `100010`,
|
|
107
|
+
`100013`, `100018`, `100022`, `100998`). Auf eine Zahlung sind sie deren
|
|
108
|
+
Ablehnung, auf eine Statusabfrage sagen sie nichts ueber den gesuchten
|
|
109
|
+
Vorgang (gemessen fuer `100108`). Die Klaerung liest den Status deshalb
|
|
110
|
+
ueber `isConclusiveAsStatus` -- sonst haette ein gesperrtes Terminal eine
|
|
111
|
+
verlorene Zahlung als "nicht belastet" ausgewiesen.
|
|
112
|
+
- **`HpsPaymentResult.reason`** traegt fuer jeden Ausgang den Grund, den Satz
|
|
113
|
+
fuer den Bediener gibt `HPS_REASON_HINTS`. Gesetzt, wo entschieden wurde:
|
|
114
|
+
bestaetigter Abbruch `aborted`, HTTP 409 `terminalBusy`, eine ueber die
|
|
115
|
+
Zwei-9027-Regel geklaerte Zahlung mit dem Grund ihres eigenen Codes.
|
|
116
|
+
`isHostUncertainResult` sagt einer spaeteren Nachfrage, dass ein `9027` dort
|
|
117
|
+
nicht "nicht belastet" heisst.
|
|
118
|
+
- `hpsCodeInfo`, `hpsCodeReason` und die Namen aller neuen Codes
|
|
119
|
+
(`CARD_READ_FAILED_CODE` usw.) sind exportiert.
|
|
120
|
+
- Der Nachweis nennt bei einer Ablehnung den hobex-Titel mit
|
|
121
|
+
(`Terminal: abgelehnt (100015 "Card declined")`).
|
|
122
|
+
- `fixtures/hobex-hps-codes.json` fuehrt je Code zusaetzlich `title`,
|
|
123
|
+
`effect`, `reason`, `source` und die Saetze je Grund (`gruende`).
|
|
124
|
+
|
|
7
125
|
## 0.9.4
|
|
8
126
|
|
|
9
127
|
### `qrModus` faengt bei `auto` an — sonst stellte die Vorgabe den Altbestand um
|
package/README.md
CHANGED
|
@@ -344,6 +344,47 @@ app.post('/kasseneck-webhook', express.raw({ type: '*/*' }), async (req, res) =>
|
|
|
344
344
|
|
|
345
345
|
So zieht sich niemand den React-Adapter in ein Node-Programm.
|
|
346
346
|
|
|
347
|
+
## Der QR-Code passt aufs Papier
|
|
348
|
+
|
|
349
|
+
Der native QR-Befehl bekommt eine Modulgröße in Druckpunkten mit und rechnet
|
|
350
|
+
selbst nicht nach, ob das Symbol samt Ruhezone auf die Rolle geht. Zu breit
|
|
351
|
+
heißt bei den meisten Bondruckern nicht „abgeschnitten", sondern **gar kein
|
|
352
|
+
QR** — auf einem Pflichtbeleg der schlechteste aller Ausgänge. Deshalb rechnet
|
|
353
|
+
dieses Paket die Größe, statt sie zu setzen:
|
|
354
|
+
|
|
355
|
+
```ts
|
|
356
|
+
import { qrGroesseFuer, QR_DRUCK_PUNKTE } from '@kreiseck/kasseneck-api/printing';
|
|
357
|
+
|
|
358
|
+
const mass = qrGroesseFuer({ nutzlast: beleg.qr, papierbreitePunkte: QR_DRUCK_PUNKTE.mm58 });
|
|
359
|
+
// mass.punkte: Punkte je Modul, null = passt auch mit der Ausnahmegröße nicht
|
|
360
|
+
// mass.unterMindestmass: gedruckt, aber unter 4 Punkten je Modul
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Am Belegweg passiert das von selbst. `qrGroesse` ist ein **Deckel**, keine
|
|
364
|
+
Vorgabe: gedruckt wird die größte Größe, die noch passt, höchstens aber der
|
|
365
|
+
Deckel. `auto` (Vorgabe) deckelt beim Bestandswert 4 — ohne ausdrückliche Wahl
|
|
366
|
+
ändert sich also kein Byte.
|
|
367
|
+
|
|
368
|
+
```ts
|
|
369
|
+
import { escPosLayoutErgebnis } from '@kreiseck/kasseneck-api/receipt';
|
|
370
|
+
|
|
371
|
+
const { bytes, qrFehler, qrAusweich } = escPosLayoutErgebnis(layout, {
|
|
372
|
+
qrGroesse: 'gross', // 'auto' | 'klein' | 'mittel' | 'gross'
|
|
373
|
+
qrModus: 'nativeModel1', // ältere Drucker, die nur Modell 1 können
|
|
374
|
+
qrMatrix: rasterFuer, // Notausgang: der QR als Bild statt gar nicht
|
|
375
|
+
});
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Der Epson-Weg (`eposPrintXml` / `eposDirectPrint`) rechnet genauso;
|
|
379
|
+
`eposPrintXmlErgebnis` gibt dort `{ xml, qrFehler, qrAusweich }`. Sein
|
|
380
|
+
Bestandswert ist 6, deshalb ist die Vorgabe dort der Deckel `mittel`.
|
|
381
|
+
|
|
382
|
+
`qrFehler` heißt „Beleg ohne QR" — das gehört dem Kunden gesagt. `qrAusweich`
|
|
383
|
+
heißt „gedruckt, aber der eingestellte Weg taugt für dieses Gerät nicht" — das
|
|
384
|
+
gehört dem Chef gesagt. Den Bildweg fährt das Paket nur mit einem `qrMatrix`,
|
|
385
|
+
das die Nutzlast in ein fertiges Raster übersetzt: hier wird bewusst weder ein
|
|
386
|
+
QR gerechnet noch ein Bild verarbeitet.
|
|
387
|
+
|
|
347
388
|
## Hobex HPS über Kasseneck Connect
|
|
348
389
|
|
|
349
390
|
Ein Browser hat weiterhin keine rohen TCP-Sockets — ein **direkter**
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
export { type HpsConnectCancelOptions, type HpsConnectClient, type HpsConnectClientOptions, type HpsConnectFetch, type HpsConnectFetchResponse, type HpsConnectPaymentOptions, type HpsConnectRefundOptions, type HpsConnectTarget, type HpsConnectTransactionOptions, createHpsConnectClient, } from './connect-client.js';
|
|
21
21
|
export { HpsClarifyTimeoutError, HpsConnectException, HpsConnectTerminalError, HpsConnectTransportError, HpsPreflightError, HpsTransactionIdError, PREFLIGHT_CONNECT_CODES, } from './errors.js';
|
|
22
22
|
export { type HpsPaymentEvent, type HpsPaymentEventKind, type HpsPaymentObserver, } from './events.js';
|
|
23
|
-
export { type CardPaymentOutcome, type HpsPaymentResult, mayRetrySafely, } from './outcome.js';
|
|
23
|
+
export { type CardPaymentOutcome, type HpsPaymentResult, isHostUncertainResult, mayRetrySafely, } from './outcome.js';
|
|
24
24
|
export { type HpsCancelOptions, type HpsPaymentOptions, type HpsPayments, type HpsPaymentsOptions, type HpsRefundOptions, createHpsPayments, } from './payments.js';
|
|
25
25
|
export { MAX_TRANSACTION_ID_LENGTH, createHpsTransactionIdGenerator, isValidHpsTransactionId, newHpsTransactionId, type HpsTransactionIdGeneratorOptions, } from './transaction-id.js';
|
|
26
|
-
export { ABORTED_CODE, APPROVED_CODE, CARD_NOT_PRESENT_CODE, HPS_MEASURED_CODES, INVALID_TRANSACTION_CODE, NOT_ABORTABLE_CODE, INVALID_AMOUNT_CODE, AMOUNT_OUT_OF_RANGE_CODE, INVALID_TID_CODE, WRONG_PIN_CODE, NO_STATEMENT_CODE, TECHNICAL_ERROR_CODE, TERMINAL_BUSY_HTTP_STATUS, TRANSACTION_CANCELED_CODE, isApproved, isCanceled, isConclusive, isInProgress, isNoStatement, isNotAbortable, isTechnicalError, isUnknownCode, parseHpsTransactionResponse, type HpsMeasuredCode, type HpsTransactionResponse, } from './transaction-response.js';
|
|
26
|
+
export { ABORTED_CODE, APP_SELECT_FAILED_CODE, APPROVED_CODE, BAD_REQUEST_CODE, CARD_DECLINED_CODE, CARD_INFO_NOT_ENTERED_CODE, CARD_NOT_PRESENT_CODE, CARD_NOT_SUPPORTED_CODE, CARD_READ_FAILED_CODE, CHIP_DATA_MISMATCH_CODE, COMPLETION_FAILED_CODE, DIAGNOSIS_FAILED_CODE, HOST_COMMUNICATION_FAILED_CODE, HOST_STEP_FAILED_CODE, HOST_TIMEOUT_REVERSED_CODE, HPS_CODES, HPS_MEASURED_CODES, HPS_REASON_HINTS, INTERNAL_ERROR_CODE, INVALID_MESSAGE_TYPE_CODE, INVALID_TID_DOCUMENTED_CODE, INVALID_TX_TYPE_CODE, MAX_RETRIES_EXCEEDED_CODE, NOT_FOUND_CODE, PASSWORD_NOT_ENTERED_CODE, REFUND_DISABLED_CODE, REFUND_PASSWORD_INVALID_CODE, SCEP_ENROLLMENT_FAILED_CODE, TERMINAL_BLOCKED_CODE, TERMINAL_BUSY_CODE, TIP_SELECTION_FAILED_CODE, UNSUPPORTED_USER_DATA_CODE, hpsCodeInfo, hpsCodeReason, isHostUncertain, isHostUncertainReason, INVALID_TRANSACTION_CODE, NOT_ABORTABLE_CODE, INVALID_AMOUNT_CODE, AMOUNT_OUT_OF_RANGE_CODE, INVALID_TID_CODE, WRONG_PIN_CODE, NO_STATEMENT_CODE, TECHNICAL_ERROR_CODE, TERMINAL_BUSY_HTTP_STATUS, TRANSACTION_CANCELED_CODE, isApproved, isCanceled, isConclusive, isConclusiveAsStatus, isInProgress, isNoStatement, isNotAbortable, isTechnicalError, isUnknownCode, parseHpsTransactionResponse, type HpsCode, type HpsCodeEffect, type HpsCodeReason, type HpsCodeSource, type HpsMeasuredCode, type HpsTransactionResponse, } from './transaction-response.js';
|
|
27
27
|
export { hobexReceiptFromHps } from './receipt.js';
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
* des Aufrufers.
|
|
20
20
|
*/
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
-
exports.
|
|
22
|
+
exports.isHostUncertain = exports.hpsCodeReason = exports.hpsCodeInfo = exports.UNSUPPORTED_USER_DATA_CODE = exports.TIP_SELECTION_FAILED_CODE = exports.TERMINAL_BUSY_CODE = exports.TERMINAL_BLOCKED_CODE = exports.SCEP_ENROLLMENT_FAILED_CODE = exports.REFUND_PASSWORD_INVALID_CODE = exports.REFUND_DISABLED_CODE = exports.PASSWORD_NOT_ENTERED_CODE = exports.NOT_FOUND_CODE = exports.MAX_RETRIES_EXCEEDED_CODE = exports.INVALID_TX_TYPE_CODE = exports.INVALID_TID_DOCUMENTED_CODE = exports.INVALID_MESSAGE_TYPE_CODE = exports.INTERNAL_ERROR_CODE = exports.HPS_REASON_HINTS = exports.HPS_MEASURED_CODES = exports.HPS_CODES = exports.HOST_TIMEOUT_REVERSED_CODE = exports.HOST_STEP_FAILED_CODE = exports.HOST_COMMUNICATION_FAILED_CODE = exports.DIAGNOSIS_FAILED_CODE = exports.COMPLETION_FAILED_CODE = exports.CHIP_DATA_MISMATCH_CODE = exports.CARD_READ_FAILED_CODE = exports.CARD_NOT_SUPPORTED_CODE = exports.CARD_NOT_PRESENT_CODE = exports.CARD_INFO_NOT_ENTERED_CODE = exports.CARD_DECLINED_CODE = exports.BAD_REQUEST_CODE = exports.APPROVED_CODE = exports.APP_SELECT_FAILED_CODE = exports.ABORTED_CODE = exports.newHpsTransactionId = exports.isValidHpsTransactionId = exports.createHpsTransactionIdGenerator = exports.MAX_TRANSACTION_ID_LENGTH = exports.createHpsPayments = exports.mayRetrySafely = exports.isHostUncertainResult = exports.PREFLIGHT_CONNECT_CODES = exports.HpsTransactionIdError = exports.HpsPreflightError = exports.HpsConnectTransportError = exports.HpsConnectTerminalError = exports.HpsConnectException = exports.HpsClarifyTimeoutError = exports.createHpsConnectClient = void 0;
|
|
23
|
+
exports.hobexReceiptFromHps = exports.parseHpsTransactionResponse = exports.isUnknownCode = exports.isTechnicalError = exports.isNotAbortable = exports.isNoStatement = exports.isInProgress = exports.isConclusiveAsStatus = exports.isConclusive = exports.isCanceled = exports.isApproved = exports.TRANSACTION_CANCELED_CODE = exports.TERMINAL_BUSY_HTTP_STATUS = exports.TECHNICAL_ERROR_CODE = exports.NO_STATEMENT_CODE = exports.WRONG_PIN_CODE = exports.INVALID_TID_CODE = exports.AMOUNT_OUT_OF_RANGE_CODE = exports.INVALID_AMOUNT_CODE = exports.NOT_ABORTABLE_CODE = exports.INVALID_TRANSACTION_CODE = exports.isHostUncertainReason = void 0;
|
|
23
24
|
var connect_client_js_1 = require("./connect-client.js");
|
|
24
25
|
Object.defineProperty(exports, "createHpsConnectClient", { enumerable: true, get: function () { return connect_client_js_1.createHpsConnectClient; } });
|
|
25
26
|
var errors_js_1 = require("./errors.js");
|
|
@@ -31,6 +32,7 @@ Object.defineProperty(exports, "HpsPreflightError", { enumerable: true, get: fun
|
|
|
31
32
|
Object.defineProperty(exports, "HpsTransactionIdError", { enumerable: true, get: function () { return errors_js_1.HpsTransactionIdError; } });
|
|
32
33
|
Object.defineProperty(exports, "PREFLIGHT_CONNECT_CODES", { enumerable: true, get: function () { return errors_js_1.PREFLIGHT_CONNECT_CODES; } });
|
|
33
34
|
var outcome_js_1 = require("./outcome.js");
|
|
35
|
+
Object.defineProperty(exports, "isHostUncertainResult", { enumerable: true, get: function () { return outcome_js_1.isHostUncertainResult; } });
|
|
34
36
|
Object.defineProperty(exports, "mayRetrySafely", { enumerable: true, get: function () { return outcome_js_1.mayRetrySafely; } });
|
|
35
37
|
var payments_js_1 = require("./payments.js");
|
|
36
38
|
Object.defineProperty(exports, "createHpsPayments", { enumerable: true, get: function () { return payments_js_1.createHpsPayments; } });
|
|
@@ -41,9 +43,41 @@ Object.defineProperty(exports, "isValidHpsTransactionId", { enumerable: true, ge
|
|
|
41
43
|
Object.defineProperty(exports, "newHpsTransactionId", { enumerable: true, get: function () { return transaction_id_js_1.newHpsTransactionId; } });
|
|
42
44
|
var transaction_response_js_1 = require("./transaction-response.js");
|
|
43
45
|
Object.defineProperty(exports, "ABORTED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.ABORTED_CODE; } });
|
|
46
|
+
Object.defineProperty(exports, "APP_SELECT_FAILED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.APP_SELECT_FAILED_CODE; } });
|
|
44
47
|
Object.defineProperty(exports, "APPROVED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.APPROVED_CODE; } });
|
|
48
|
+
Object.defineProperty(exports, "BAD_REQUEST_CODE", { enumerable: true, get: function () { return transaction_response_js_1.BAD_REQUEST_CODE; } });
|
|
49
|
+
Object.defineProperty(exports, "CARD_DECLINED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.CARD_DECLINED_CODE; } });
|
|
50
|
+
Object.defineProperty(exports, "CARD_INFO_NOT_ENTERED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.CARD_INFO_NOT_ENTERED_CODE; } });
|
|
45
51
|
Object.defineProperty(exports, "CARD_NOT_PRESENT_CODE", { enumerable: true, get: function () { return transaction_response_js_1.CARD_NOT_PRESENT_CODE; } });
|
|
52
|
+
Object.defineProperty(exports, "CARD_NOT_SUPPORTED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.CARD_NOT_SUPPORTED_CODE; } });
|
|
53
|
+
Object.defineProperty(exports, "CARD_READ_FAILED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.CARD_READ_FAILED_CODE; } });
|
|
54
|
+
Object.defineProperty(exports, "CHIP_DATA_MISMATCH_CODE", { enumerable: true, get: function () { return transaction_response_js_1.CHIP_DATA_MISMATCH_CODE; } });
|
|
55
|
+
Object.defineProperty(exports, "COMPLETION_FAILED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.COMPLETION_FAILED_CODE; } });
|
|
56
|
+
Object.defineProperty(exports, "DIAGNOSIS_FAILED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.DIAGNOSIS_FAILED_CODE; } });
|
|
57
|
+
Object.defineProperty(exports, "HOST_COMMUNICATION_FAILED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.HOST_COMMUNICATION_FAILED_CODE; } });
|
|
58
|
+
Object.defineProperty(exports, "HOST_STEP_FAILED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.HOST_STEP_FAILED_CODE; } });
|
|
59
|
+
Object.defineProperty(exports, "HOST_TIMEOUT_REVERSED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.HOST_TIMEOUT_REVERSED_CODE; } });
|
|
60
|
+
Object.defineProperty(exports, "HPS_CODES", { enumerable: true, get: function () { return transaction_response_js_1.HPS_CODES; } });
|
|
46
61
|
Object.defineProperty(exports, "HPS_MEASURED_CODES", { enumerable: true, get: function () { return transaction_response_js_1.HPS_MEASURED_CODES; } });
|
|
62
|
+
Object.defineProperty(exports, "HPS_REASON_HINTS", { enumerable: true, get: function () { return transaction_response_js_1.HPS_REASON_HINTS; } });
|
|
63
|
+
Object.defineProperty(exports, "INTERNAL_ERROR_CODE", { enumerable: true, get: function () { return transaction_response_js_1.INTERNAL_ERROR_CODE; } });
|
|
64
|
+
Object.defineProperty(exports, "INVALID_MESSAGE_TYPE_CODE", { enumerable: true, get: function () { return transaction_response_js_1.INVALID_MESSAGE_TYPE_CODE; } });
|
|
65
|
+
Object.defineProperty(exports, "INVALID_TID_DOCUMENTED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.INVALID_TID_DOCUMENTED_CODE; } });
|
|
66
|
+
Object.defineProperty(exports, "INVALID_TX_TYPE_CODE", { enumerable: true, get: function () { return transaction_response_js_1.INVALID_TX_TYPE_CODE; } });
|
|
67
|
+
Object.defineProperty(exports, "MAX_RETRIES_EXCEEDED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.MAX_RETRIES_EXCEEDED_CODE; } });
|
|
68
|
+
Object.defineProperty(exports, "NOT_FOUND_CODE", { enumerable: true, get: function () { return transaction_response_js_1.NOT_FOUND_CODE; } });
|
|
69
|
+
Object.defineProperty(exports, "PASSWORD_NOT_ENTERED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.PASSWORD_NOT_ENTERED_CODE; } });
|
|
70
|
+
Object.defineProperty(exports, "REFUND_DISABLED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.REFUND_DISABLED_CODE; } });
|
|
71
|
+
Object.defineProperty(exports, "REFUND_PASSWORD_INVALID_CODE", { enumerable: true, get: function () { return transaction_response_js_1.REFUND_PASSWORD_INVALID_CODE; } });
|
|
72
|
+
Object.defineProperty(exports, "SCEP_ENROLLMENT_FAILED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.SCEP_ENROLLMENT_FAILED_CODE; } });
|
|
73
|
+
Object.defineProperty(exports, "TERMINAL_BLOCKED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.TERMINAL_BLOCKED_CODE; } });
|
|
74
|
+
Object.defineProperty(exports, "TERMINAL_BUSY_CODE", { enumerable: true, get: function () { return transaction_response_js_1.TERMINAL_BUSY_CODE; } });
|
|
75
|
+
Object.defineProperty(exports, "TIP_SELECTION_FAILED_CODE", { enumerable: true, get: function () { return transaction_response_js_1.TIP_SELECTION_FAILED_CODE; } });
|
|
76
|
+
Object.defineProperty(exports, "UNSUPPORTED_USER_DATA_CODE", { enumerable: true, get: function () { return transaction_response_js_1.UNSUPPORTED_USER_DATA_CODE; } });
|
|
77
|
+
Object.defineProperty(exports, "hpsCodeInfo", { enumerable: true, get: function () { return transaction_response_js_1.hpsCodeInfo; } });
|
|
78
|
+
Object.defineProperty(exports, "hpsCodeReason", { enumerable: true, get: function () { return transaction_response_js_1.hpsCodeReason; } });
|
|
79
|
+
Object.defineProperty(exports, "isHostUncertain", { enumerable: true, get: function () { return transaction_response_js_1.isHostUncertain; } });
|
|
80
|
+
Object.defineProperty(exports, "isHostUncertainReason", { enumerable: true, get: function () { return transaction_response_js_1.isHostUncertainReason; } });
|
|
47
81
|
Object.defineProperty(exports, "INVALID_TRANSACTION_CODE", { enumerable: true, get: function () { return transaction_response_js_1.INVALID_TRANSACTION_CODE; } });
|
|
48
82
|
Object.defineProperty(exports, "NOT_ABORTABLE_CODE", { enumerable: true, get: function () { return transaction_response_js_1.NOT_ABORTABLE_CODE; } });
|
|
49
83
|
Object.defineProperty(exports, "INVALID_AMOUNT_CODE", { enumerable: true, get: function () { return transaction_response_js_1.INVALID_AMOUNT_CODE; } });
|
|
@@ -57,6 +91,7 @@ Object.defineProperty(exports, "TRANSACTION_CANCELED_CODE", { enumerable: true,
|
|
|
57
91
|
Object.defineProperty(exports, "isApproved", { enumerable: true, get: function () { return transaction_response_js_1.isApproved; } });
|
|
58
92
|
Object.defineProperty(exports, "isCanceled", { enumerable: true, get: function () { return transaction_response_js_1.isCanceled; } });
|
|
59
93
|
Object.defineProperty(exports, "isConclusive", { enumerable: true, get: function () { return transaction_response_js_1.isConclusive; } });
|
|
94
|
+
Object.defineProperty(exports, "isConclusiveAsStatus", { enumerable: true, get: function () { return transaction_response_js_1.isConclusiveAsStatus; } });
|
|
60
95
|
Object.defineProperty(exports, "isInProgress", { enumerable: true, get: function () { return transaction_response_js_1.isInProgress; } });
|
|
61
96
|
Object.defineProperty(exports, "isNoStatement", { enumerable: true, get: function () { return transaction_response_js_1.isNoStatement; } });
|
|
62
97
|
Object.defineProperty(exports, "isNotAbortable", { enumerable: true, get: function () { return transaction_response_js_1.isNotAbortable; } });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type HpsCodeReason, type HpsTransactionResponse } from './transaction-response.js';
|
|
2
2
|
/**
|
|
3
3
|
* Ausgang eines Kartenzahlvorgangs — die einzige Frage, die ein Aufrufer
|
|
4
4
|
* wirklich hat: darf ich es nochmal versuchen?
|
|
@@ -35,6 +35,18 @@ export interface HpsPaymentResult {
|
|
|
35
35
|
* Entscheidung getragen. Bei schluessigem Ausgang nicht gesetzt.
|
|
36
36
|
*/
|
|
37
37
|
readonly lastResponse?: HpsTransactionResponse;
|
|
38
|
+
/**
|
|
39
|
+
* Worauf die Kasse reagiert -- der Grund hinter dem Ausgang, mit dem Satz
|
|
40
|
+
* fuer den Bediener in `HPS_REASON_HINTS`.
|
|
41
|
+
*
|
|
42
|
+
* Gesetzt an der Stelle, die den Ausgang entschieden hat, nicht aus
|
|
43
|
+
* [response] abgeleitet: ein bestaetigter Abbruch antwortet `'0'` und ist
|
|
44
|
+
* trotzdem `'aborted'`, und wenn die Zwei-9027-Regel eine Zahlung als
|
|
45
|
+
* abgelehnt klaert, zaehlt der Code der ZAHLUNG, nicht das `9027` danach.
|
|
46
|
+
* Fehlt, wenn kein Code etwas erklaert (die Leitung riss ab, bevor das
|
|
47
|
+
* Terminal etwas sagte) und bei einer Aufhebung, die nicht gegriffen hat.
|
|
48
|
+
*/
|
|
49
|
+
readonly reason?: HpsCodeReason;
|
|
38
50
|
/**
|
|
39
51
|
* Verlauf der Klaerung, in Reihenfolge — der Nachweis, der im
|
|
40
52
|
* Belastungsstreit gelesen wird. Behauptet nie eine Ursache, die nicht
|
|
@@ -44,3 +56,10 @@ export interface HpsPaymentResult {
|
|
|
44
56
|
}
|
|
45
57
|
/** Nur bei `'declined'` steht fest, dass nichts belastet wurde. */
|
|
46
58
|
export declare function mayRetrySafely(result: Pick<HpsPaymentResult, 'outcome'>): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* `true`, wenn der Ausgang offen ist, weil das Terminal eine Stoerung beim
|
|
61
|
+
* oder nach dem hobex-Host meldete (`effect: 'hostUncertain'`). Wichtig fuer
|
|
62
|
+
* jede SPAETERE Nachfrage: antwortet die Statusabfrage dann `9027`, heisst das
|
|
63
|
+
* hier NICHT "nichts belastet".
|
|
64
|
+
*/
|
|
65
|
+
export declare function isHostUncertainResult(result: Pick<HpsPaymentResult, 'outcome' | 'reason'>): boolean;
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.mayRetrySafely = mayRetrySafely;
|
|
4
|
+
exports.isHostUncertainResult = isHostUncertainResult;
|
|
5
|
+
const transaction_response_js_1 = require("./transaction-response.js");
|
|
4
6
|
/** Nur bei `'declined'` steht fest, dass nichts belastet wurde. */
|
|
5
7
|
function mayRetrySafely(result) {
|
|
6
8
|
return result.outcome === 'declined';
|
|
7
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* `true`, wenn der Ausgang offen ist, weil das Terminal eine Stoerung beim
|
|
12
|
+
* oder nach dem hobex-Host meldete (`effect: 'hostUncertain'`). Wichtig fuer
|
|
13
|
+
* jede SPAETERE Nachfrage: antwortet die Statusabfrage dann `9027`, heisst das
|
|
14
|
+
* hier NICHT "nichts belastet".
|
|
15
|
+
*/
|
|
16
|
+
function isHostUncertainResult(result) {
|
|
17
|
+
return result.outcome === 'unresolved' && (0, transaction_response_js_1.isHostUncertainReason)(result.reason);
|
|
18
|
+
}
|
|
@@ -89,6 +89,25 @@ import type { HpsPaymentResult } from './outcome.js';
|
|
|
89
89
|
* Kein [tryAbort]-Versuch bei [cancel]: die Originalzahlung ist laengst
|
|
90
90
|
* abgeschlossen und antwortet gemessen mit `100010` -- ein Abbruch darauf
|
|
91
91
|
* waere sinnlos.
|
|
92
|
+
*
|
|
93
|
+
* ## Stoerung beim Host: die Klaerung darf nichts schliessen (11.09.2026)
|
|
94
|
+
*
|
|
95
|
+
* Die Antwortcodeliste von hobex benennt Codes, bei denen der Host beteiligt
|
|
96
|
+
* war und das Terminal NICHT selbst storniert (`effect: 'hostUncertain'`,
|
|
97
|
+
* etwa `100007`). Fuer sie gilt zweierlei:
|
|
98
|
+
*
|
|
99
|
+
* 1. Die Zwei-9027-Regel ([ausGeschlossenerAntwort]) greift nicht. Sie
|
|
100
|
+
* schliesst aus "das Terminal hat geantwortet und nichts gespeichert" auf
|
|
101
|
+
* "nichts belastet" -- das stimmt fuer einen Vorgang, der am Terminal
|
|
102
|
+
* endete, aber nicht fuer einen, dessen Ausgang beim Host liegt. Dasselbe
|
|
103
|
+
* gilt sinngemaess fuer [cancel]: ein unveraendertes `'0'` auf die
|
|
104
|
+
* Originalzahlung beweist dann nicht, dass die Aufhebung beim Host nicht
|
|
105
|
+
* ankam.
|
|
106
|
+
* 2. Die Klaerung wartet trotzdem nicht das ganze Budget ab. Sagt die
|
|
107
|
+
* Statusabfrage zweimal in Folge nichts Neues (`9027` oder erneut ein
|
|
108
|
+
* solcher Code), endet sie sofort als `unresolved` -- das Terminal wird es
|
|
109
|
+
* auch in 90 Sekunden nicht wissen. Meldet sie dagegen `'0'`, ist die
|
|
110
|
+
* Zahlung genehmigt, ganz normal.
|
|
92
111
|
*/
|
|
93
112
|
export interface HpsPaymentsOptions {
|
|
94
113
|
/** Wie lange insgesamt geklaert wird, bevor der Ausgang offen bleibt. Vorgabe 90 s. */
|