@kreiseck/kasseneck-api 0.9.4 → 0.10.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 +45 -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/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/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,51 @@ 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.10.0
|
|
8
|
+
|
|
9
|
+
### Die Antwortcodeliste von hobex — jeder Code eingeordnet, jeder Ausgang mit Grund
|
|
10
|
+
|
|
11
|
+
**Anlass:** hobex hat am 11.09.2026 die Antwortcodeliste der HPS-Anwendung
|
|
12
|
+
geschickt. Drei der Codes kamen seit dem 28.08.2026 im Betrieb vor (`100004`,
|
|
13
|
+
`100005`, `100015`) und waren bis jetzt ungedeutet. Jede Zahlung damit lief in
|
|
14
|
+
die Klaerung und endete erst ueber die Zwei-9027-Regel. Zwilling:
|
|
15
|
+
`kasseneck_api` 6.9.0, Begruendungen dort in `doc/kartenzahlung.md`.
|
|
16
|
+
|
|
17
|
+
- **`HPS_CODES`** fuehrt alle 31 Codes der Liste zusammen mit den gemessenen:
|
|
18
|
+
Code, hobex-Titel, Bedeutung, Wirkung (`effect`), Grund (`reason`) und
|
|
19
|
+
Quelle (`source`). `isConclusive` liest seine Positivliste daraus.
|
|
20
|
+
`HPS_MEASURED_CODES` bleibt als abgekuendigter Name fuer dieselbe Tabelle.
|
|
21
|
+
- **Was vor dem Host scheitert, ist eine Ablehnung** (Kartenlesen, EMV-Kernel,
|
|
22
|
+
Eingaben am Geraet, Geraetezustand, fehlerhafte Anfrage) -- `declined`, ohne
|
|
23
|
+
Abbruch und ohne Statusabfrage. Dazu `100029`: das Terminal storniert laut
|
|
24
|
+
hobex selbst.
|
|
25
|
+
- **Neu: `effect: 'hostUncertain'`** (`isHostUncertain`) fuer `100006`,
|
|
26
|
+
`100007`, `100023`, `100024`, `100026`, `100027`, `100999`. Der Host war
|
|
27
|
+
beteiligt, das Terminal storniert nicht selbst. Die Zwei-9027-Regel greift
|
|
28
|
+
hier **nicht**; die Klaerung endet nach zwei Abfragen ohne Neues als
|
|
29
|
+
`unresolved`, nur ein `'0'` entscheidet danach noch, und ein Abbruchversuch
|
|
30
|
+
entfaellt. Bei einer Aufhebung entscheidet ein unveraendertes `'0'` auf die
|
|
31
|
+
Originalzahlung dann ebenfalls nichts.
|
|
32
|
+
- **`rejectsRequest` / `isConclusiveAsStatus`:** zehn Codes weisen die Anfrage
|
|
33
|
+
selbst ab (`9002`, `100001`, `100008`, `100108`, `100009`, `100010`,
|
|
34
|
+
`100013`, `100018`, `100022`, `100998`). Auf eine Zahlung sind sie deren
|
|
35
|
+
Ablehnung, auf eine Statusabfrage sagen sie nichts ueber den gesuchten
|
|
36
|
+
Vorgang (gemessen fuer `100108`). Die Klaerung liest den Status deshalb
|
|
37
|
+
ueber `isConclusiveAsStatus` -- sonst haette ein gesperrtes Terminal eine
|
|
38
|
+
verlorene Zahlung als "nicht belastet" ausgewiesen.
|
|
39
|
+
- **`HpsPaymentResult.reason`** traegt fuer jeden Ausgang den Grund, den Satz
|
|
40
|
+
fuer den Bediener gibt `HPS_REASON_HINTS`. Gesetzt, wo entschieden wurde:
|
|
41
|
+
bestaetigter Abbruch `aborted`, HTTP 409 `terminalBusy`, eine ueber die
|
|
42
|
+
Zwei-9027-Regel geklaerte Zahlung mit dem Grund ihres eigenen Codes.
|
|
43
|
+
`isHostUncertainResult` sagt einer spaeteren Nachfrage, dass ein `9027` dort
|
|
44
|
+
nicht "nicht belastet" heisst.
|
|
45
|
+
- `hpsCodeInfo`, `hpsCodeReason` und die Namen aller neuen Codes
|
|
46
|
+
(`CARD_READ_FAILED_CODE` usw.) sind exportiert.
|
|
47
|
+
- Der Nachweis nennt bei einer Ablehnung den hobex-Titel mit
|
|
48
|
+
(`Terminal: abgelehnt (100015 "Card declined")`).
|
|
49
|
+
- `fixtures/hobex-hps-codes.json` fuehrt je Code zusaetzlich `title`,
|
|
50
|
+
`effect`, `reason`, `source` und die Saetze je Grund (`gruende`).
|
|
51
|
+
|
|
7
52
|
## 0.9.4
|
|
8
53
|
|
|
9
54
|
### `qrModus` faengt bei `auto` an — sonst stellte die Vorgabe den Altbestand um
|
|
@@ -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. */
|
|
@@ -59,7 +59,34 @@ function createHpsPayments(client, target, options = {}) {
|
|
|
59
59
|
return null;
|
|
60
60
|
steps.push('Terminal beschaeftigt (HTTP 409) -- die Anfrage wurde nicht angenommen, es ist nichts geschehen');
|
|
61
61
|
emit('resolved', steps[steps.length - 1], id);
|
|
62
|
-
return { outcome: 'declined', transactionId: id, steps: [...steps] };
|
|
62
|
+
return { outcome: 'declined', transactionId: id, reason: 'terminalBusy', steps: [...steps] };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Benennt einen Code mit `effect: 'hostUncertain'` fuer den Nachweis: was
|
|
66
|
+
* das Terminal meldet, mit Code und hobex-Titel. Die Folgerung setzt der
|
|
67
|
+
* Aufrufer dazu.
|
|
68
|
+
*/
|
|
69
|
+
function stoerung(res) {
|
|
70
|
+
const info = (0, transaction_response_js_1.hpsCodeInfo)(res.responseCode);
|
|
71
|
+
const was = info.reason === 'internalError'
|
|
72
|
+
? 'interner Fehler des Terminals'
|
|
73
|
+
: 'Stoerung zwischen Terminal und hobex-Host, das Terminal storniert nicht selbst';
|
|
74
|
+
return `Terminal meldet ${was} (${info.code} "${info.title}")`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Der Grund eines offenen Ausgangs. [antwort] ist die Antwort auf die
|
|
78
|
+
* ERZEUGENDE Anfrage (oder die zuerst gemeldete Stoerung), [letzte] die
|
|
79
|
+
* zuletzt gelesene Statusabfrage. Eine Stoerung beim Host geht vor; sonst
|
|
80
|
+
* erklaert der Code der erzeugenden Anfrage mehr als ein `9027` danach.
|
|
81
|
+
*/
|
|
82
|
+
function offenerGrund(antwort, letzte) {
|
|
83
|
+
if (antwort && (0, transaction_response_js_1.isHostUncertain)(antwort))
|
|
84
|
+
return (0, transaction_response_js_1.hpsCodeReason)(antwort.responseCode);
|
|
85
|
+
if (letzte && (0, transaction_response_js_1.isHostUncertain)(letzte))
|
|
86
|
+
return (0, transaction_response_js_1.hpsCodeReason)(letzte.responseCode);
|
|
87
|
+
if (antwort?.responseCode !== undefined)
|
|
88
|
+
return (0, transaction_response_js_1.hpsCodeReason)(antwort.responseCode);
|
|
89
|
+
return (0, transaction_response_js_1.hpsCodeReason)(letzte?.responseCode);
|
|
63
90
|
}
|
|
64
91
|
/** Verlaufseintrag fuer eine direkte Antwort, die den Ausgang NICHT festschreibt. */
|
|
65
92
|
function offeneAntwort(res) {
|
|
@@ -69,6 +96,12 @@ function createHpsPayments(client, target, options = {}) {
|
|
|
69
96
|
if ((0, transaction_response_js_1.isTechnicalError)(res)) {
|
|
70
97
|
return `Antwort mit technischem Fehler (${transaction_response_js_1.TECHNICAL_ERROR_CODE}) -- keine Aussage ueber den Vorgang, Ausgang wird geklaert`;
|
|
71
98
|
}
|
|
99
|
+
if ((0, transaction_response_js_1.isHostUncertain)(res)) {
|
|
100
|
+
return `${stoerung(res)} -- ob belastet wurde, weiss das Terminal nicht, Ausgang wird geklaert`;
|
|
101
|
+
}
|
|
102
|
+
if (res.responseCode === transaction_response_js_1.NOT_FOUND_CODE) {
|
|
103
|
+
return `Terminal kennt den Vorgang nicht (${res.responseCode} "Not Found") -- keine Aussage, Ausgang wird geklaert`;
|
|
104
|
+
}
|
|
72
105
|
if ((0, transaction_response_js_1.isUnknownCode)(res)) {
|
|
73
106
|
return `Terminal nennt einen unbekannten Code (${res.responseCode})${klartext(res)} -- Ausgang wird geklaert`;
|
|
74
107
|
}
|
|
@@ -82,6 +115,22 @@ function createHpsPayments(client, target, options = {}) {
|
|
|
82
115
|
if ((0, transaction_response_js_1.isTechnicalError)(status)) {
|
|
83
116
|
return `Status: technischer Fehler (${transaction_response_js_1.TECHNICAL_ERROR_CODE}) -- keine Aussage ueber den Vorgang`;
|
|
84
117
|
}
|
|
118
|
+
if ((0, transaction_response_js_1.isHostUncertain)(status)) {
|
|
119
|
+
return `Status: ${stoerung(status)} -- keine Aussage`;
|
|
120
|
+
}
|
|
121
|
+
// Bewusst NICHT "keine Auskunft": das Wort steht fuer das gemessene 9027,
|
|
122
|
+
// und Aufrufer lesen es als solches (sastre, OpenCardPaymentService).
|
|
123
|
+
if (status.responseCode === transaction_response_js_1.NOT_FOUND_CODE) {
|
|
124
|
+
return `Status: Vorgang nicht gefunden (${status.responseCode}) -- keine Aussage`;
|
|
125
|
+
}
|
|
126
|
+
const info = (0, transaction_response_js_1.hpsCodeInfo)(status.responseCode);
|
|
127
|
+
if (info?.rejectsRequest) {
|
|
128
|
+
return `Status: Abfrage abgewiesen (${info.code} "${info.title}") -- keine Aussage ueber den Vorgang`;
|
|
129
|
+
}
|
|
130
|
+
if (info?.conclusive && !(0, transaction_response_js_1.isApproved)(status)) {
|
|
131
|
+
// Nur erreichbar nach einer Stoerung beim Host, siehe [resolve].
|
|
132
|
+
return `Status: abgelehnt (${info.code} "${info.title}") -- nach der Stoerung beim hobex-Host entscheidet nur eine Genehmigung`;
|
|
133
|
+
}
|
|
85
134
|
if ((0, transaction_response_js_1.isUnknownCode)(status)) {
|
|
86
135
|
return `Status: unbekannter Code (${status.responseCode})${klartext(status)} -- keine Aussage`;
|
|
87
136
|
}
|
|
@@ -98,14 +147,27 @@ function createHpsPayments(client, target, options = {}) {
|
|
|
98
147
|
const text = res.responseText?.trim();
|
|
99
148
|
return text ? ` "${text}"` : '';
|
|
100
149
|
}
|
|
101
|
-
/**
|
|
102
|
-
|
|
150
|
+
/**
|
|
151
|
+
* Ordnet eine Terminal-Antwort ein. `null`, wenn sie nichts entscheidet.
|
|
152
|
+
*
|
|
153
|
+
* [aufhebung]: die Antwort gehoert zu [cancel]. Ein `'0'` heisst dort
|
|
154
|
+
* "aufgehoben", und der Grund ist `'canceled'` statt `'approved'`.
|
|
155
|
+
*/
|
|
156
|
+
function fromResponse(res, id, steps, aufhebung = false) {
|
|
103
157
|
if (!(0, transaction_response_js_1.isConclusive)(res))
|
|
104
158
|
return null;
|
|
105
159
|
const approved = res.responseCode === '0';
|
|
106
|
-
steps.push(approved
|
|
160
|
+
steps.push(approved
|
|
161
|
+
? 'Terminal: genehmigt'
|
|
162
|
+
: `Terminal: abgelehnt (${res.responseCode} "${(0, transaction_response_js_1.hpsCodeInfo)(res.responseCode).title}")`);
|
|
107
163
|
emit('resolved', steps[steps.length - 1], id);
|
|
108
|
-
return {
|
|
164
|
+
return {
|
|
165
|
+
outcome: approved ? 'approved' : 'declined',
|
|
166
|
+
transactionId: id,
|
|
167
|
+
response: res,
|
|
168
|
+
reason: approved && aufhebung ? 'canceled' : (0, transaction_response_js_1.hpsCodeReason)(res.responseCode),
|
|
169
|
+
steps: [...steps],
|
|
170
|
+
};
|
|
109
171
|
}
|
|
110
172
|
/**
|
|
111
173
|
* Ordnet die DIREKTE Antwort auf einen Aufhebungs-Request ein. Fast dasselbe
|
|
@@ -131,7 +193,7 @@ function createHpsPayments(client, target, options = {}) {
|
|
|
131
193
|
steps.push(`Aufhebung mit ${transaction_response_js_1.TRANSACTION_CANCELED_CODE} beantwortet -- mehrdeutig, der Zustand der Originalzahlung wird abgefragt`);
|
|
132
194
|
return null;
|
|
133
195
|
}
|
|
134
|
-
return fromResponse(res, id, steps);
|
|
196
|
+
return fromResponse(res, id, steps, true);
|
|
135
197
|
}
|
|
136
198
|
/**
|
|
137
199
|
* Ordnet die Statusabfrage einer OFFENEN AUFHEBUNG ein. `null`, wenn sie
|
|
@@ -186,7 +248,7 @@ function createHpsPayments(client, target, options = {}) {
|
|
|
186
248
|
if (voided) {
|
|
187
249
|
steps.push(`Terminal: Aufhebung bestaetigt (${status.responseCode ?? status.state})`);
|
|
188
250
|
emit('resolved', steps[steps.length - 1], id);
|
|
189
|
-
return { outcome: 'approved', transactionId: id, response: status, steps: [...steps] };
|
|
251
|
+
return { outcome: 'approved', transactionId: id, response: status, reason: 'canceled', steps: [...steps] };
|
|
190
252
|
}
|
|
191
253
|
if ((0, transaction_response_js_1.isApproved)(status)) {
|
|
192
254
|
if (firstQuery) {
|
|
@@ -202,14 +264,15 @@ function createHpsPayments(client, target, options = {}) {
|
|
|
202
264
|
/**
|
|
203
265
|
* [letzteAntwort] ist die letzte Antwort, die das Terminal in dieser
|
|
204
266
|
* Klaerung gab -- als `lastResponse` fuer Anzeige und Katalog,
|
|
205
|
-
* ausdruecklich NICHT als `response`.
|
|
267
|
+
* ausdruecklich NICHT als `response`. [grund] siehe [offenerGrund].
|
|
206
268
|
*/
|
|
207
|
-
function open(id, steps, letzteAntwort) {
|
|
269
|
+
function open(id, steps, letzteAntwort, grund) {
|
|
208
270
|
emit('resolved', steps[steps.length - 1], id);
|
|
209
271
|
return {
|
|
210
272
|
outcome: 'unresolved',
|
|
211
273
|
transactionId: id,
|
|
212
274
|
...(letzteAntwort ? { lastResponse: letzteAntwort } : {}),
|
|
275
|
+
...(grund ? { reason: grund } : {}),
|
|
213
276
|
steps: [...steps],
|
|
214
277
|
};
|
|
215
278
|
}
|
|
@@ -274,26 +337,46 @@ function createHpsPayments(client, target, options = {}) {
|
|
|
274
337
|
}
|
|
275
338
|
steps.push('Abbruch bestaetigt -- der Vorgang war noch abbrechbar, es ist nichts belastet');
|
|
276
339
|
emit('resolved', steps[steps.length - 1], id);
|
|
277
|
-
return { outcome: 'declined', transactionId: id, response: res, steps: [...steps] };
|
|
340
|
+
return { outcome: 'declined', transactionId: id, response: res, reason: 'aborted', steps: [...steps] };
|
|
278
341
|
}
|
|
279
|
-
/** Klaert einen offenen Ausgang: erst abbrechen, dann abfragen -- bis das Terminal etwas sagt oder das Budget aufgebraucht ist. */
|
|
280
342
|
/**
|
|
281
|
-
*
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
* [
|
|
285
|
-
* nicht
|
|
343
|
+
* Klaert einen offenen Ausgang: erst abbrechen, dann abfragen -- bis das
|
|
344
|
+
* Terminal etwas sagt oder das Budget aufgebraucht ist.
|
|
345
|
+
*
|
|
346
|
+
* [antwort] ist die Antwort auf die ERZEUGENDE Anfrage, sofern eine kam.
|
|
347
|
+
* Traegt sie einen Ergebniscode, dessen Bedeutung wir nur nicht kennen, ist
|
|
348
|
+
* der Vorgang am Geraet abgeschlossen -- und erst dadurch bekommt
|
|
349
|
+
* `9027` beim Pollen einen Aussagewert, den es sonst nicht hat. Siehe
|
|
350
|
+
* [ausGeschlossenerAntwort]. Meldet sie eine Stoerung beim Host
|
|
351
|
+
* ([isHostUncertain]), bekommt `9027` diesen Aussagewert gerade NICHT --
|
|
352
|
+
* siehe Klassendoku, "Stoerung beim Host".
|
|
286
353
|
*/
|
|
287
|
-
async function resolve(id, steps,
|
|
354
|
+
async function resolve(id, steps, antwort) {
|
|
288
355
|
emit('resolving', 'Ausgang offen, Klaerung laeuft', id);
|
|
289
356
|
const start = now();
|
|
290
357
|
const elapsedMs = () => now() - start;
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
358
|
+
const antwortMitCode = antwort?.responseCode !== undefined;
|
|
359
|
+
// Einmal gemeldet, bleibt die Stoerung stehen -- auch wenn erst die
|
|
360
|
+
// Statusabfrage sie nennt und danach 9027 kommt.
|
|
361
|
+
let stoerungsAntwort = antwort && (0, transaction_response_js_1.isHostUncertain)(antwort) ? antwort : undefined;
|
|
362
|
+
let letzteAntwort = antwort;
|
|
363
|
+
if (stoerungsAntwort === undefined) {
|
|
364
|
+
const aborted = await tryAbort(id, steps, elapsedMs);
|
|
365
|
+
if (aborted)
|
|
366
|
+
return aborted;
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
// Der Vorgang ist am Terminal schon beendet -- mit einer Stoerung beim
|
|
370
|
+
// Host. Ein quittierter Abbruch bewiese nur, dass am Terminal nichts mehr
|
|
371
|
+
// laeuft, nicht, dass der Host nichts belastet hat.
|
|
372
|
+
steps.push('Kein Abbruchversuch -- das Terminal hat den Vorgang mit einer Stoerung beim hobex-Host beendet');
|
|
373
|
+
}
|
|
294
374
|
let wait = 0;
|
|
295
375
|
let transportFailures = 0;
|
|
296
376
|
let ohneAuskunft = 0;
|
|
377
|
+
// Beantwortete Statusabfragen in Folge, die zu einem Vorgang mit
|
|
378
|
+
// Host-Stoerung nichts Neues sagen.
|
|
379
|
+
let stoerungOhneNeues = 0;
|
|
297
380
|
while (elapsedMs() < resolveBudgetMs) {
|
|
298
381
|
if (wait > 0) {
|
|
299
382
|
const left = resolveBudgetMs - elapsedMs();
|
|
@@ -318,23 +401,45 @@ function createHpsPayments(client, target, options = {}) {
|
|
|
318
401
|
wait = nextWait(wait);
|
|
319
402
|
continue;
|
|
320
403
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
404
|
+
if ((0, transaction_response_js_1.isHostUncertain)(status))
|
|
405
|
+
stoerungsAntwort ??= status;
|
|
406
|
+
const hostUngewiss = stoerungsAntwort !== undefined;
|
|
407
|
+
// Auf die Statusabfrage entscheidet nur ein Code, der den gesuchten
|
|
408
|
+
// Vorgang beschreibt -- nicht einer, der diese Abfrage abweist
|
|
409
|
+
// ([isConclusiveAsStatus]). Nach einer Stoerung beim Host entscheidet nur
|
|
410
|
+
// noch eine Genehmigung: jede andere Aussage des Terminals betrifft seinen
|
|
411
|
+
// Speicher, nicht den des Hosts.
|
|
412
|
+
if (hostUngewiss ? (0, transaction_response_js_1.isApproved)(status) : (0, transaction_response_js_1.isConclusiveAsStatus)(status)) {
|
|
413
|
+
const settled = fromResponse(status, id, steps);
|
|
414
|
+
if (settled)
|
|
415
|
+
return settled;
|
|
416
|
+
}
|
|
324
417
|
if ((0, transaction_response_js_1.isNoStatement)(status)) {
|
|
325
418
|
ohneAuskunft += 1;
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
419
|
+
if (!hostUngewiss) {
|
|
420
|
+
const geklaert = ausGeschlossenerAntwort(id, steps, status, antwortMitCode ? antwort : undefined, ohneAuskunft);
|
|
421
|
+
if (geklaert)
|
|
422
|
+
return geklaert;
|
|
423
|
+
}
|
|
329
424
|
}
|
|
330
425
|
else {
|
|
331
426
|
ohneAuskunft = 0;
|
|
332
427
|
}
|
|
428
|
+
// Nach einer Stoerung ist jede Antwort ausser '0' (die oben schon
|
|
429
|
+
// entschieden hat) "nichts Neues".
|
|
430
|
+
stoerungOhneNeues = hostUngewiss ? stoerungOhneNeues + 1 : 0;
|
|
333
431
|
steps.push(statusOhneErgebnis(status) ?? 'Status: noch kein Ergebniscode');
|
|
432
|
+
if (stoerungOhneNeues >= 2) {
|
|
433
|
+
// Siehe Klassendoku, "Stoerung beim Host": das Terminal weiss es
|
|
434
|
+
// nicht, und es wird es auch nicht wissen, wenn wir weiterfragen.
|
|
435
|
+
steps.push('Statusabfrage zweimal ohne Neues nach einer Stoerung beim hobex-Host -- '
|
|
436
|
+
+ 'das Terminal kann nicht sagen, ob belastet wurde, Ausgang bleibt offen');
|
|
437
|
+
return open(id, steps, letzteAntwort, offenerGrund(stoerungsAntwort ?? antwort, letzteAntwort));
|
|
438
|
+
}
|
|
334
439
|
wait = nextWait(wait);
|
|
335
440
|
}
|
|
336
441
|
steps.push('Ausgang bleibt offen');
|
|
337
|
-
return open(id, steps, letzteAntwort);
|
|
442
|
+
return open(id, steps, letzteAntwort, offenerGrund(stoerungsAntwort ?? antwort, letzteAntwort));
|
|
338
443
|
}
|
|
339
444
|
/**
|
|
340
445
|
* Liest `9027` beim Pollen als "nicht genehmigt" -- aber NUR, wenn das
|
|
@@ -359,10 +464,15 @@ function createHpsPayments(client, target, options = {}) {
|
|
|
359
464
|
* entstuende die Doppelbelastung vom 24.08.2026 an einer neuen Stelle.
|
|
360
465
|
* Dieselbe Absicherung traegt bereits [fromCancelStatus].
|
|
361
466
|
*
|
|
467
|
+
* [antwort] ist die Antwort MIT Code auf die erzeugende Anfrage -- oder
|
|
468
|
+
* `undefined`, wenn keine kam; dann greift die Regel nicht. Ihr Code ergibt
|
|
469
|
+
* den `reason`: er erklaert den Ausgang, das `9027` danach nicht. Der
|
|
470
|
+
* Aufrufer ruft diese Regel NICHT fuer eine Stoerung beim Host.
|
|
471
|
+
*
|
|
362
472
|
* `undefined` heisst: nicht entschieden, weiter pollen.
|
|
363
473
|
*/
|
|
364
|
-
function ausGeschlossenerAntwort(id, steps, status,
|
|
365
|
-
if (!
|
|
474
|
+
function ausGeschlossenerAntwort(id, steps, status, antwort, ohneAuskunft) {
|
|
475
|
+
if (!antwort)
|
|
366
476
|
return undefined;
|
|
367
477
|
if (ohneAuskunft < 2)
|
|
368
478
|
return undefined;
|
|
@@ -374,6 +484,7 @@ function createHpsPayments(client, target, options = {}) {
|
|
|
374
484
|
outcome: 'declined',
|
|
375
485
|
transactionId: id,
|
|
376
486
|
response: status,
|
|
487
|
+
reason: (0, transaction_response_js_1.hpsCodeReason)(antwort.responseCode),
|
|
377
488
|
steps: [...steps],
|
|
378
489
|
};
|
|
379
490
|
}
|
|
@@ -393,11 +504,17 @@ function createHpsPayments(client, target, options = {}) {
|
|
|
393
504
|
*
|
|
394
505
|
* Budget, Backoff und Transportfehler-Deckelung sind unveraendert aus
|
|
395
506
|
* [resolve] uebernommen.
|
|
507
|
+
*
|
|
508
|
+
* [antwort] ist die direkte Antwort auf den Aufhebungs-Request, sofern eine
|
|
509
|
+
* kam. Meldete sie eine Stoerung beim Host, entscheidet ein unveraendertes
|
|
510
|
+
* `'0'` nichts -- siehe Klassendoku, "Stoerung beim Host".
|
|
396
511
|
*/
|
|
397
|
-
async function resolveCancel(id, steps,
|
|
512
|
+
async function resolveCancel(id, steps, antwort) {
|
|
398
513
|
emit('resolving', 'Ausgang offen, Klaerung laeuft', id);
|
|
399
514
|
const start = now();
|
|
400
515
|
const elapsedMs = () => now() - start;
|
|
516
|
+
const hostUngewiss = antwort !== undefined && (0, transaction_response_js_1.isHostUncertain)(antwort);
|
|
517
|
+
let letzteAntwort = antwort;
|
|
401
518
|
let wait = 0;
|
|
402
519
|
let transportFailures = 0;
|
|
403
520
|
// Zaehlt nur BEANTWORTETE Statusabfragen -- Grundlage der Karenz fuer den
|
|
@@ -428,6 +545,16 @@ function createHpsPayments(client, target, options = {}) {
|
|
|
428
545
|
wait = nextWait(wait);
|
|
429
546
|
continue;
|
|
430
547
|
}
|
|
548
|
+
if (hostUngewiss && (0, transaction_response_js_1.isApproved)(status) && answeredQueries >= 2) {
|
|
549
|
+
// Siehe Klassendoku, "Stoerung beim Host": das unveraenderte '0'
|
|
550
|
+
// spiegelt nur den Speicher des Terminals. "Hat nicht gegriffen"
|
|
551
|
+
// fuehrte nach dem Tagesabschluss zu einer Rueckerstattung, die der
|
|
552
|
+
// Kunde doppelt bekaeme, falls der Host die Aufhebung doch verbucht hat.
|
|
553
|
+
steps.push('Terminal: Originalzahlung steht unveraendert (0), aber die Aufhebung endete mit einer '
|
|
554
|
+
+ 'Stoerung beim hobex-Host -- ob sie dort gewirkt hat, kann das Terminal nicht sagen, '
|
|
555
|
+
+ 'Ausgang bleibt offen');
|
|
556
|
+
return open(id, steps, letzteAntwort, offenerGrund(antwort, letzteAntwort));
|
|
557
|
+
}
|
|
431
558
|
const settled = fromCancelStatus(status, id, steps, answeredQueries === 1);
|
|
432
559
|
if (settled)
|
|
433
560
|
return settled;
|
|
@@ -439,7 +566,7 @@ function createHpsPayments(client, target, options = {}) {
|
|
|
439
566
|
wait = nextWait(wait);
|
|
440
567
|
}
|
|
441
568
|
steps.push('Ausgang bleibt offen');
|
|
442
|
-
return open(id, steps, letzteAntwort);
|
|
569
|
+
return open(id, steps, letzteAntwort, offenerGrund(antwort, letzteAntwort));
|
|
443
570
|
}
|
|
444
571
|
async function pay(paymentOptions) {
|
|
445
572
|
const id = paymentOptions.transactionId ?? (0, transaction_id_js_1.newHpsTransactionId)();
|
|
@@ -478,7 +605,7 @@ function createHpsPayments(client, target, options = {}) {
|
|
|
478
605
|
return settled;
|
|
479
606
|
steps.push(offeneAntwort(res));
|
|
480
607
|
}
|
|
481
|
-
return resolve(id, steps, res
|
|
608
|
+
return resolve(id, steps, res);
|
|
482
609
|
}
|
|
483
610
|
/**
|
|
484
611
|
* Gutschrift mit geklaertem Ausgang -- EXAKT derselbe Klaerweg wie [pay]
|
|
@@ -522,7 +649,7 @@ function createHpsPayments(client, target, options = {}) {
|
|
|
522
649
|
// Dieselbe Klaerfunktion wie [pay]: die Kennung ist die des NEUEN
|
|
523
650
|
// Vorgangs, eine Statusabfrage darauf liefert also genau dessen Ausgang,
|
|
524
651
|
// und der Abbruch ist derselbe Diskriminator wie bei einer Zahlung.
|
|
525
|
-
return resolve(id, steps, res
|
|
652
|
+
return resolve(id, steps, res);
|
|
526
653
|
}
|
|
527
654
|
/**
|
|
528
655
|
* Aufhebung (Storno/Void) einer bestehenden Zahlung mit geklaertem Ausgang.
|