@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 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.hobexReceiptFromHps = exports.parseHpsTransactionResponse = exports.isUnknownCode = exports.isTechnicalError = exports.isNotAbortable = exports.isNoStatement = exports.isInProgress = 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.HPS_MEASURED_CODES = exports.CARD_NOT_PRESENT_CODE = exports.APPROVED_CODE = exports.ABORTED_CODE = exports.newHpsTransactionId = exports.isValidHpsTransactionId = exports.createHpsTransactionIdGenerator = exports.MAX_TRANSACTION_ID_LENGTH = exports.createHpsPayments = exports.mayRetrySafely = exports.PREFLIGHT_CONNECT_CODES = exports.HpsTransactionIdError = exports.HpsPreflightError = exports.HpsConnectTransportError = exports.HpsConnectTerminalError = exports.HpsConnectException = exports.HpsClarifyTimeoutError = exports.createHpsConnectClient = void 0;
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 { HpsTransactionResponse } from './transaction-response.js';
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
- /** Ordnet eine Terminal-Antwort ein. `null`, wenn sie nichts entscheidet. */
102
- function fromResponse(res, id, steps) {
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 ? 'Terminal: genehmigt' : `Terminal: abgelehnt (${res.responseCode})`);
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 { outcome: approved ? 'approved' : 'declined', transactionId: id, response: res, steps: [...steps] };
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
- * `antwortMitCode` heisst: das Terminal hat auf die ERZEUGENDE Anfrage eine
282
- * Antwort MIT Ergebniscode geliefert, deren Bedeutung wir nur nicht kennen.
283
- * Dann ist der Vorgang am Geraet abgeschlossen -- und erst dadurch bekommt
284
- * [NO_STATEMENT_CODE] (`9027`) beim Pollen einen Aussagewert, den es sonst
285
- * nicht hat. Siehe [ausGeschlossenerAntwort].
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, antwortMitCode = false, letzteAntwort) {
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 aborted = await tryAbort(id, steps, elapsedMs);
292
- if (aborted)
293
- return aborted;
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
- const settled = fromResponse(status, id, steps);
322
- if (settled)
323
- return settled;
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
- const geklaert = ausGeschlossenerAntwort(id, steps, status, antwortMitCode, ohneAuskunft);
327
- if (geklaert)
328
- return geklaert;
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, antwortMitCode, ohneAuskunft) {
365
- if (!antwortMitCode)
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, letzteAntwort) {
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?.responseCode !== undefined, 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?.responseCode !== undefined, res);
652
+ return resolve(id, steps, res);
526
653
  }
527
654
  /**
528
655
  * Aufhebung (Storno/Void) einer bestehenden Zahlung mit geklaertem Ausgang.