@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HpsClarifyTimeoutError, HpsConnectException, HpsConnectTerminalError, HpsPreflightError, } from './errors.js';
|
|
2
2
|
import { newHpsTransactionId } from './transaction-id.js';
|
|
3
|
-
import { isApproved, isCanceled, isConclusive, isNoStatement, isNotAbortable, isTechnicalError, isUnknownCode, NOT_ABORTABLE_CODE, TECHNICAL_ERROR_CODE, TRANSACTION_CANCELED_CODE, } from './transaction-response.js';
|
|
3
|
+
import { hpsCodeInfo, hpsCodeReason, isApproved, isCanceled, isConclusive, isConclusiveAsStatus, isHostUncertain, isNoStatement, isNotAbortable, isTechnicalError, isUnknownCode, NOT_ABORTABLE_CODE, NOT_FOUND_CODE, TECHNICAL_ERROR_CODE, TRANSACTION_CANCELED_CODE, } from './transaction-response.js';
|
|
4
4
|
/** Teiler, mit dem das Abbruchbudget aus [HpsPaymentsOptions.resolveBudgetMs] entsteht. */
|
|
5
5
|
const ABORT_BUDGET_DIVISOR = 6;
|
|
6
6
|
export function createHpsPayments(client, target, options = {}) {
|
|
@@ -56,7 +56,34 @@ export function createHpsPayments(client, target, options = {}) {
|
|
|
56
56
|
return null;
|
|
57
57
|
steps.push('Terminal beschaeftigt (HTTP 409) -- die Anfrage wurde nicht angenommen, es ist nichts geschehen');
|
|
58
58
|
emit('resolved', steps[steps.length - 1], id);
|
|
59
|
-
return { outcome: 'declined', transactionId: id, steps: [...steps] };
|
|
59
|
+
return { outcome: 'declined', transactionId: id, reason: 'terminalBusy', steps: [...steps] };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Benennt einen Code mit `effect: 'hostUncertain'` fuer den Nachweis: was
|
|
63
|
+
* das Terminal meldet, mit Code und hobex-Titel. Die Folgerung setzt der
|
|
64
|
+
* Aufrufer dazu.
|
|
65
|
+
*/
|
|
66
|
+
function stoerung(res) {
|
|
67
|
+
const info = hpsCodeInfo(res.responseCode);
|
|
68
|
+
const was = info.reason === 'internalError'
|
|
69
|
+
? 'interner Fehler des Terminals'
|
|
70
|
+
: 'Stoerung zwischen Terminal und hobex-Host, das Terminal storniert nicht selbst';
|
|
71
|
+
return `Terminal meldet ${was} (${info.code} "${info.title}")`;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Der Grund eines offenen Ausgangs. [antwort] ist die Antwort auf die
|
|
75
|
+
* ERZEUGENDE Anfrage (oder die zuerst gemeldete Stoerung), [letzte] die
|
|
76
|
+
* zuletzt gelesene Statusabfrage. Eine Stoerung beim Host geht vor; sonst
|
|
77
|
+
* erklaert der Code der erzeugenden Anfrage mehr als ein `9027` danach.
|
|
78
|
+
*/
|
|
79
|
+
function offenerGrund(antwort, letzte) {
|
|
80
|
+
if (antwort && isHostUncertain(antwort))
|
|
81
|
+
return hpsCodeReason(antwort.responseCode);
|
|
82
|
+
if (letzte && isHostUncertain(letzte))
|
|
83
|
+
return hpsCodeReason(letzte.responseCode);
|
|
84
|
+
if (antwort?.responseCode !== undefined)
|
|
85
|
+
return hpsCodeReason(antwort.responseCode);
|
|
86
|
+
return hpsCodeReason(letzte?.responseCode);
|
|
60
87
|
}
|
|
61
88
|
/** Verlaufseintrag fuer eine direkte Antwort, die den Ausgang NICHT festschreibt. */
|
|
62
89
|
function offeneAntwort(res) {
|
|
@@ -66,6 +93,12 @@ export function createHpsPayments(client, target, options = {}) {
|
|
|
66
93
|
if (isTechnicalError(res)) {
|
|
67
94
|
return `Antwort mit technischem Fehler (${TECHNICAL_ERROR_CODE}) -- keine Aussage ueber den Vorgang, Ausgang wird geklaert`;
|
|
68
95
|
}
|
|
96
|
+
if (isHostUncertain(res)) {
|
|
97
|
+
return `${stoerung(res)} -- ob belastet wurde, weiss das Terminal nicht, Ausgang wird geklaert`;
|
|
98
|
+
}
|
|
99
|
+
if (res.responseCode === NOT_FOUND_CODE) {
|
|
100
|
+
return `Terminal kennt den Vorgang nicht (${res.responseCode} "Not Found") -- keine Aussage, Ausgang wird geklaert`;
|
|
101
|
+
}
|
|
69
102
|
if (isUnknownCode(res)) {
|
|
70
103
|
return `Terminal nennt einen unbekannten Code (${res.responseCode})${klartext(res)} -- Ausgang wird geklaert`;
|
|
71
104
|
}
|
|
@@ -79,6 +112,22 @@ export function createHpsPayments(client, target, options = {}) {
|
|
|
79
112
|
if (isTechnicalError(status)) {
|
|
80
113
|
return `Status: technischer Fehler (${TECHNICAL_ERROR_CODE}) -- keine Aussage ueber den Vorgang`;
|
|
81
114
|
}
|
|
115
|
+
if (isHostUncertain(status)) {
|
|
116
|
+
return `Status: ${stoerung(status)} -- keine Aussage`;
|
|
117
|
+
}
|
|
118
|
+
// Bewusst NICHT "keine Auskunft": das Wort steht fuer das gemessene 9027,
|
|
119
|
+
// und Aufrufer lesen es als solches (sastre, OpenCardPaymentService).
|
|
120
|
+
if (status.responseCode === NOT_FOUND_CODE) {
|
|
121
|
+
return `Status: Vorgang nicht gefunden (${status.responseCode}) -- keine Aussage`;
|
|
122
|
+
}
|
|
123
|
+
const info = hpsCodeInfo(status.responseCode);
|
|
124
|
+
if (info?.rejectsRequest) {
|
|
125
|
+
return `Status: Abfrage abgewiesen (${info.code} "${info.title}") -- keine Aussage ueber den Vorgang`;
|
|
126
|
+
}
|
|
127
|
+
if (info?.conclusive && !isApproved(status)) {
|
|
128
|
+
// Nur erreichbar nach einer Stoerung beim Host, siehe [resolve].
|
|
129
|
+
return `Status: abgelehnt (${info.code} "${info.title}") -- nach der Stoerung beim hobex-Host entscheidet nur eine Genehmigung`;
|
|
130
|
+
}
|
|
82
131
|
if (isUnknownCode(status)) {
|
|
83
132
|
return `Status: unbekannter Code (${status.responseCode})${klartext(status)} -- keine Aussage`;
|
|
84
133
|
}
|
|
@@ -95,14 +144,27 @@ export function createHpsPayments(client, target, options = {}) {
|
|
|
95
144
|
const text = res.responseText?.trim();
|
|
96
145
|
return text ? ` "${text}"` : '';
|
|
97
146
|
}
|
|
98
|
-
/**
|
|
99
|
-
|
|
147
|
+
/**
|
|
148
|
+
* Ordnet eine Terminal-Antwort ein. `null`, wenn sie nichts entscheidet.
|
|
149
|
+
*
|
|
150
|
+
* [aufhebung]: die Antwort gehoert zu [cancel]. Ein `'0'` heisst dort
|
|
151
|
+
* "aufgehoben", und der Grund ist `'canceled'` statt `'approved'`.
|
|
152
|
+
*/
|
|
153
|
+
function fromResponse(res, id, steps, aufhebung = false) {
|
|
100
154
|
if (!isConclusive(res))
|
|
101
155
|
return null;
|
|
102
156
|
const approved = res.responseCode === '0';
|
|
103
|
-
steps.push(approved
|
|
157
|
+
steps.push(approved
|
|
158
|
+
? 'Terminal: genehmigt'
|
|
159
|
+
: `Terminal: abgelehnt (${res.responseCode} "${hpsCodeInfo(res.responseCode).title}")`);
|
|
104
160
|
emit('resolved', steps[steps.length - 1], id);
|
|
105
|
-
return {
|
|
161
|
+
return {
|
|
162
|
+
outcome: approved ? 'approved' : 'declined',
|
|
163
|
+
transactionId: id,
|
|
164
|
+
response: res,
|
|
165
|
+
reason: approved && aufhebung ? 'canceled' : hpsCodeReason(res.responseCode),
|
|
166
|
+
steps: [...steps],
|
|
167
|
+
};
|
|
106
168
|
}
|
|
107
169
|
/**
|
|
108
170
|
* Ordnet die DIREKTE Antwort auf einen Aufhebungs-Request ein. Fast dasselbe
|
|
@@ -128,7 +190,7 @@ export function createHpsPayments(client, target, options = {}) {
|
|
|
128
190
|
steps.push(`Aufhebung mit ${TRANSACTION_CANCELED_CODE} beantwortet -- mehrdeutig, der Zustand der Originalzahlung wird abgefragt`);
|
|
129
191
|
return null;
|
|
130
192
|
}
|
|
131
|
-
return fromResponse(res, id, steps);
|
|
193
|
+
return fromResponse(res, id, steps, true);
|
|
132
194
|
}
|
|
133
195
|
/**
|
|
134
196
|
* Ordnet die Statusabfrage einer OFFENEN AUFHEBUNG ein. `null`, wenn sie
|
|
@@ -183,7 +245,7 @@ export function createHpsPayments(client, target, options = {}) {
|
|
|
183
245
|
if (voided) {
|
|
184
246
|
steps.push(`Terminal: Aufhebung bestaetigt (${status.responseCode ?? status.state})`);
|
|
185
247
|
emit('resolved', steps[steps.length - 1], id);
|
|
186
|
-
return { outcome: 'approved', transactionId: id, response: status, steps: [...steps] };
|
|
248
|
+
return { outcome: 'approved', transactionId: id, response: status, reason: 'canceled', steps: [...steps] };
|
|
187
249
|
}
|
|
188
250
|
if (isApproved(status)) {
|
|
189
251
|
if (firstQuery) {
|
|
@@ -199,14 +261,15 @@ export function createHpsPayments(client, target, options = {}) {
|
|
|
199
261
|
/**
|
|
200
262
|
* [letzteAntwort] ist die letzte Antwort, die das Terminal in dieser
|
|
201
263
|
* Klaerung gab -- als `lastResponse` fuer Anzeige und Katalog,
|
|
202
|
-
* ausdruecklich NICHT als `response`.
|
|
264
|
+
* ausdruecklich NICHT als `response`. [grund] siehe [offenerGrund].
|
|
203
265
|
*/
|
|
204
|
-
function open(id, steps, letzteAntwort) {
|
|
266
|
+
function open(id, steps, letzteAntwort, grund) {
|
|
205
267
|
emit('resolved', steps[steps.length - 1], id);
|
|
206
268
|
return {
|
|
207
269
|
outcome: 'unresolved',
|
|
208
270
|
transactionId: id,
|
|
209
271
|
...(letzteAntwort ? { lastResponse: letzteAntwort } : {}),
|
|
272
|
+
...(grund ? { reason: grund } : {}),
|
|
210
273
|
steps: [...steps],
|
|
211
274
|
};
|
|
212
275
|
}
|
|
@@ -271,26 +334,46 @@ export function createHpsPayments(client, target, options = {}) {
|
|
|
271
334
|
}
|
|
272
335
|
steps.push('Abbruch bestaetigt -- der Vorgang war noch abbrechbar, es ist nichts belastet');
|
|
273
336
|
emit('resolved', steps[steps.length - 1], id);
|
|
274
|
-
return { outcome: 'declined', transactionId: id, response: res, steps: [...steps] };
|
|
337
|
+
return { outcome: 'declined', transactionId: id, response: res, reason: 'aborted', steps: [...steps] };
|
|
275
338
|
}
|
|
276
|
-
/** Klaert einen offenen Ausgang: erst abbrechen, dann abfragen -- bis das Terminal etwas sagt oder das Budget aufgebraucht ist. */
|
|
277
339
|
/**
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
* [
|
|
282
|
-
* nicht
|
|
340
|
+
* Klaert einen offenen Ausgang: erst abbrechen, dann abfragen -- bis das
|
|
341
|
+
* Terminal etwas sagt oder das Budget aufgebraucht ist.
|
|
342
|
+
*
|
|
343
|
+
* [antwort] ist die Antwort auf die ERZEUGENDE Anfrage, sofern eine kam.
|
|
344
|
+
* Traegt sie einen Ergebniscode, dessen Bedeutung wir nur nicht kennen, ist
|
|
345
|
+
* der Vorgang am Geraet abgeschlossen -- und erst dadurch bekommt
|
|
346
|
+
* `9027` beim Pollen einen Aussagewert, den es sonst nicht hat. Siehe
|
|
347
|
+
* [ausGeschlossenerAntwort]. Meldet sie eine Stoerung beim Host
|
|
348
|
+
* ([isHostUncertain]), bekommt `9027` diesen Aussagewert gerade NICHT --
|
|
349
|
+
* siehe Klassendoku, "Stoerung beim Host".
|
|
283
350
|
*/
|
|
284
|
-
async function resolve(id, steps,
|
|
351
|
+
async function resolve(id, steps, antwort) {
|
|
285
352
|
emit('resolving', 'Ausgang offen, Klaerung laeuft', id);
|
|
286
353
|
const start = now();
|
|
287
354
|
const elapsedMs = () => now() - start;
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
|
|
355
|
+
const antwortMitCode = antwort?.responseCode !== undefined;
|
|
356
|
+
// Einmal gemeldet, bleibt die Stoerung stehen -- auch wenn erst die
|
|
357
|
+
// Statusabfrage sie nennt und danach 9027 kommt.
|
|
358
|
+
let stoerungsAntwort = antwort && isHostUncertain(antwort) ? antwort : undefined;
|
|
359
|
+
let letzteAntwort = antwort;
|
|
360
|
+
if (stoerungsAntwort === undefined) {
|
|
361
|
+
const aborted = await tryAbort(id, steps, elapsedMs);
|
|
362
|
+
if (aborted)
|
|
363
|
+
return aborted;
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
// Der Vorgang ist am Terminal schon beendet -- mit einer Stoerung beim
|
|
367
|
+
// Host. Ein quittierter Abbruch bewiese nur, dass am Terminal nichts mehr
|
|
368
|
+
// laeuft, nicht, dass der Host nichts belastet hat.
|
|
369
|
+
steps.push('Kein Abbruchversuch -- das Terminal hat den Vorgang mit einer Stoerung beim hobex-Host beendet');
|
|
370
|
+
}
|
|
291
371
|
let wait = 0;
|
|
292
372
|
let transportFailures = 0;
|
|
293
373
|
let ohneAuskunft = 0;
|
|
374
|
+
// Beantwortete Statusabfragen in Folge, die zu einem Vorgang mit
|
|
375
|
+
// Host-Stoerung nichts Neues sagen.
|
|
376
|
+
let stoerungOhneNeues = 0;
|
|
294
377
|
while (elapsedMs() < resolveBudgetMs) {
|
|
295
378
|
if (wait > 0) {
|
|
296
379
|
const left = resolveBudgetMs - elapsedMs();
|
|
@@ -315,23 +398,45 @@ export function createHpsPayments(client, target, options = {}) {
|
|
|
315
398
|
wait = nextWait(wait);
|
|
316
399
|
continue;
|
|
317
400
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
401
|
+
if (isHostUncertain(status))
|
|
402
|
+
stoerungsAntwort ??= status;
|
|
403
|
+
const hostUngewiss = stoerungsAntwort !== undefined;
|
|
404
|
+
// Auf die Statusabfrage entscheidet nur ein Code, der den gesuchten
|
|
405
|
+
// Vorgang beschreibt -- nicht einer, der diese Abfrage abweist
|
|
406
|
+
// ([isConclusiveAsStatus]). Nach einer Stoerung beim Host entscheidet nur
|
|
407
|
+
// noch eine Genehmigung: jede andere Aussage des Terminals betrifft seinen
|
|
408
|
+
// Speicher, nicht den des Hosts.
|
|
409
|
+
if (hostUngewiss ? isApproved(status) : isConclusiveAsStatus(status)) {
|
|
410
|
+
const settled = fromResponse(status, id, steps);
|
|
411
|
+
if (settled)
|
|
412
|
+
return settled;
|
|
413
|
+
}
|
|
321
414
|
if (isNoStatement(status)) {
|
|
322
415
|
ohneAuskunft += 1;
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
416
|
+
if (!hostUngewiss) {
|
|
417
|
+
const geklaert = ausGeschlossenerAntwort(id, steps, status, antwortMitCode ? antwort : undefined, ohneAuskunft);
|
|
418
|
+
if (geklaert)
|
|
419
|
+
return geklaert;
|
|
420
|
+
}
|
|
326
421
|
}
|
|
327
422
|
else {
|
|
328
423
|
ohneAuskunft = 0;
|
|
329
424
|
}
|
|
425
|
+
// Nach einer Stoerung ist jede Antwort ausser '0' (die oben schon
|
|
426
|
+
// entschieden hat) "nichts Neues".
|
|
427
|
+
stoerungOhneNeues = hostUngewiss ? stoerungOhneNeues + 1 : 0;
|
|
330
428
|
steps.push(statusOhneErgebnis(status) ?? 'Status: noch kein Ergebniscode');
|
|
429
|
+
if (stoerungOhneNeues >= 2) {
|
|
430
|
+
// Siehe Klassendoku, "Stoerung beim Host": das Terminal weiss es
|
|
431
|
+
// nicht, und es wird es auch nicht wissen, wenn wir weiterfragen.
|
|
432
|
+
steps.push('Statusabfrage zweimal ohne Neues nach einer Stoerung beim hobex-Host -- '
|
|
433
|
+
+ 'das Terminal kann nicht sagen, ob belastet wurde, Ausgang bleibt offen');
|
|
434
|
+
return open(id, steps, letzteAntwort, offenerGrund(stoerungsAntwort ?? antwort, letzteAntwort));
|
|
435
|
+
}
|
|
331
436
|
wait = nextWait(wait);
|
|
332
437
|
}
|
|
333
438
|
steps.push('Ausgang bleibt offen');
|
|
334
|
-
return open(id, steps, letzteAntwort);
|
|
439
|
+
return open(id, steps, letzteAntwort, offenerGrund(stoerungsAntwort ?? antwort, letzteAntwort));
|
|
335
440
|
}
|
|
336
441
|
/**
|
|
337
442
|
* Liest `9027` beim Pollen als "nicht genehmigt" -- aber NUR, wenn das
|
|
@@ -356,10 +461,15 @@ export function createHpsPayments(client, target, options = {}) {
|
|
|
356
461
|
* entstuende die Doppelbelastung vom 24.08.2026 an einer neuen Stelle.
|
|
357
462
|
* Dieselbe Absicherung traegt bereits [fromCancelStatus].
|
|
358
463
|
*
|
|
464
|
+
* [antwort] ist die Antwort MIT Code auf die erzeugende Anfrage -- oder
|
|
465
|
+
* `undefined`, wenn keine kam; dann greift die Regel nicht. Ihr Code ergibt
|
|
466
|
+
* den `reason`: er erklaert den Ausgang, das `9027` danach nicht. Der
|
|
467
|
+
* Aufrufer ruft diese Regel NICHT fuer eine Stoerung beim Host.
|
|
468
|
+
*
|
|
359
469
|
* `undefined` heisst: nicht entschieden, weiter pollen.
|
|
360
470
|
*/
|
|
361
|
-
function ausGeschlossenerAntwort(id, steps, status,
|
|
362
|
-
if (!
|
|
471
|
+
function ausGeschlossenerAntwort(id, steps, status, antwort, ohneAuskunft) {
|
|
472
|
+
if (!antwort)
|
|
363
473
|
return undefined;
|
|
364
474
|
if (ohneAuskunft < 2)
|
|
365
475
|
return undefined;
|
|
@@ -371,6 +481,7 @@ export function createHpsPayments(client, target, options = {}) {
|
|
|
371
481
|
outcome: 'declined',
|
|
372
482
|
transactionId: id,
|
|
373
483
|
response: status,
|
|
484
|
+
reason: hpsCodeReason(antwort.responseCode),
|
|
374
485
|
steps: [...steps],
|
|
375
486
|
};
|
|
376
487
|
}
|
|
@@ -390,11 +501,17 @@ export function createHpsPayments(client, target, options = {}) {
|
|
|
390
501
|
*
|
|
391
502
|
* Budget, Backoff und Transportfehler-Deckelung sind unveraendert aus
|
|
392
503
|
* [resolve] uebernommen.
|
|
504
|
+
*
|
|
505
|
+
* [antwort] ist die direkte Antwort auf den Aufhebungs-Request, sofern eine
|
|
506
|
+
* kam. Meldete sie eine Stoerung beim Host, entscheidet ein unveraendertes
|
|
507
|
+
* `'0'` nichts -- siehe Klassendoku, "Stoerung beim Host".
|
|
393
508
|
*/
|
|
394
|
-
async function resolveCancel(id, steps,
|
|
509
|
+
async function resolveCancel(id, steps, antwort) {
|
|
395
510
|
emit('resolving', 'Ausgang offen, Klaerung laeuft', id);
|
|
396
511
|
const start = now();
|
|
397
512
|
const elapsedMs = () => now() - start;
|
|
513
|
+
const hostUngewiss = antwort !== undefined && isHostUncertain(antwort);
|
|
514
|
+
let letzteAntwort = antwort;
|
|
398
515
|
let wait = 0;
|
|
399
516
|
let transportFailures = 0;
|
|
400
517
|
// Zaehlt nur BEANTWORTETE Statusabfragen -- Grundlage der Karenz fuer den
|
|
@@ -425,6 +542,16 @@ export function createHpsPayments(client, target, options = {}) {
|
|
|
425
542
|
wait = nextWait(wait);
|
|
426
543
|
continue;
|
|
427
544
|
}
|
|
545
|
+
if (hostUngewiss && isApproved(status) && answeredQueries >= 2) {
|
|
546
|
+
// Siehe Klassendoku, "Stoerung beim Host": das unveraenderte '0'
|
|
547
|
+
// spiegelt nur den Speicher des Terminals. "Hat nicht gegriffen"
|
|
548
|
+
// fuehrte nach dem Tagesabschluss zu einer Rueckerstattung, die der
|
|
549
|
+
// Kunde doppelt bekaeme, falls der Host die Aufhebung doch verbucht hat.
|
|
550
|
+
steps.push('Terminal: Originalzahlung steht unveraendert (0), aber die Aufhebung endete mit einer '
|
|
551
|
+
+ 'Stoerung beim hobex-Host -- ob sie dort gewirkt hat, kann das Terminal nicht sagen, '
|
|
552
|
+
+ 'Ausgang bleibt offen');
|
|
553
|
+
return open(id, steps, letzteAntwort, offenerGrund(antwort, letzteAntwort));
|
|
554
|
+
}
|
|
428
555
|
const settled = fromCancelStatus(status, id, steps, answeredQueries === 1);
|
|
429
556
|
if (settled)
|
|
430
557
|
return settled;
|
|
@@ -436,7 +563,7 @@ export function createHpsPayments(client, target, options = {}) {
|
|
|
436
563
|
wait = nextWait(wait);
|
|
437
564
|
}
|
|
438
565
|
steps.push('Ausgang bleibt offen');
|
|
439
|
-
return open(id, steps, letzteAntwort);
|
|
566
|
+
return open(id, steps, letzteAntwort, offenerGrund(antwort, letzteAntwort));
|
|
440
567
|
}
|
|
441
568
|
async function pay(paymentOptions) {
|
|
442
569
|
const id = paymentOptions.transactionId ?? newHpsTransactionId();
|
|
@@ -475,7 +602,7 @@ export function createHpsPayments(client, target, options = {}) {
|
|
|
475
602
|
return settled;
|
|
476
603
|
steps.push(offeneAntwort(res));
|
|
477
604
|
}
|
|
478
|
-
return resolve(id, steps, res
|
|
605
|
+
return resolve(id, steps, res);
|
|
479
606
|
}
|
|
480
607
|
/**
|
|
481
608
|
* Gutschrift mit geklaertem Ausgang -- EXAKT derselbe Klaerweg wie [pay]
|
|
@@ -519,7 +646,7 @@ export function createHpsPayments(client, target, options = {}) {
|
|
|
519
646
|
// Dieselbe Klaerfunktion wie [pay]: die Kennung ist die des NEUEN
|
|
520
647
|
// Vorgangs, eine Statusabfrage darauf liefert also genau dessen Ausgang,
|
|
521
648
|
// und der Abbruch ist derselbe Diskriminator wie bei einer Zahlung.
|
|
522
|
-
return resolve(id, steps, res
|
|
649
|
+
return resolve(id, steps, res);
|
|
523
650
|
}
|
|
524
651
|
/**
|
|
525
652
|
* Aufhebung (Storno/Void) einer bestehenden Zahlung mit geklaertem Ausgang.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* ein, es reicht den Terminal-Rumpf roh durch — die Einordnung passiert hier.
|
|
6
6
|
*
|
|
7
7
|
* **Zwilling:** `kasseneck_api/lib/src/hobex_hps/transaction_response.dart`.
|
|
8
|
-
* Beide Seiten pinnen dieselbe Codetabelle, siehe `
|
|
8
|
+
* Beide Seiten pinnen dieselbe Codetabelle, siehe `HPS_CODES` unten
|
|
9
9
|
* und `fixtures/hobex-hps-codes.json`.
|
|
10
10
|
*
|
|
11
11
|
* **`responseCode !== '0'` ist NICHT die Pruefung auf eine Ablehnung.** Genau
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*
|
|
19
19
|
* [isConclusive] ist die einzige Stelle, an der ein Code zu einem Ausgang
|
|
20
20
|
* wird — und sie ist eine ECHTE Positivliste: nur ein Code, dessen Bedeutung
|
|
21
|
-
*
|
|
21
|
+
* feststeht und in [HPS_CODES] benannt ist, zaehlt. Jeder andere —
|
|
22
22
|
* auch ein neuer, heute noch unbekannter Code — ist eine Wissensluecke, siehe
|
|
23
23
|
* [isUnknownCode]. Am 27.08.2026 hat der Dart-Zwilling gemessen, warum die
|
|
24
24
|
* Gegenrichtung ("jeder Code ausser 9027 ist schluessig") gefaehrlich ist: ein
|
|
@@ -26,54 +26,121 @@
|
|
|
26
26
|
* schluessig und haette eine Zahlung, unter der tatsaechlich Geld geflossen
|
|
27
27
|
* sein kann, als `declined` gemeldet.
|
|
28
28
|
*/
|
|
29
|
-
/**
|
|
29
|
+
/** Wie ein Ergebniscode den Ausgang eines Vorgangs bestimmt. */
|
|
30
|
+
export type HpsCodeEffect =
|
|
31
|
+
/** Schreibt den Ausgang fest: `'0'` genehmigt, jeder andere abgelehnt. */
|
|
32
|
+
'conclusive'
|
|
33
|
+
/** Gemessen oder dokumentiert, aber KEINE Aussage (9027, 9900, 100011). */
|
|
34
|
+
| 'noStatement'
|
|
35
|
+
/**
|
|
36
|
+
* Der Host war beteiligt, das Terminal storniert nicht selbst -- ob belastet
|
|
37
|
+
* wurde, weiss das Terminal nicht. Weiterklaeren, aber ohne dass ein
|
|
38
|
+
* spaeteres `9027` daraus "nichts belastet" machen darf (siehe `payments.ts`).
|
|
39
|
+
*/
|
|
40
|
+
| 'hostUncertain';
|
|
41
|
+
/** Woher die Bedeutung eines Codes stammt. */
|
|
42
|
+
export type HpsCodeSource =
|
|
43
|
+
/** Am Geraet gemessen (`doc/kartenzahlung.md` im Dart-Zwilling). */
|
|
44
|
+
'measured'
|
|
45
|
+
/** Aus der Antwortcodeliste von hobex (erhalten 11.09.2026). */
|
|
46
|
+
| 'documented'
|
|
47
|
+
/** Beides. */
|
|
48
|
+
| 'measuredAndDocumented';
|
|
49
|
+
/**
|
|
50
|
+
* Worauf eine Kasse reagiert -- der Grund hinter einem Ergebniscode. Mehrere
|
|
51
|
+
* Codes teilen sich einen Grund, wenn am Tresen dasselbe zu tun ist
|
|
52
|
+
* (`100004`, `100005`, `100012`: "Karte nicht gelesen, noch einmal"). Der Satz
|
|
53
|
+
* fuer den Bediener steht in [HPS_REASON_HINTS]; eine Kasse mit eigener
|
|
54
|
+
* Uebersetzung schluesselt ueber den Grund selbst.
|
|
55
|
+
*/
|
|
56
|
+
export type HpsCodeReason = 'approved' | 'aborted' | 'noCard' | 'cardReadFailed' | 'cardDeclined' | 'wrongPin' | 'amountInvalid' | 'tipNotSelected' | 'terminalBusy' | 'terminalBlocked' | 'terminalSetup' | 'terminalFault' | 'requestRejected' | 'invalidTransaction' | 'refundPassword' | 'refundDisabled' | 'hostTimeoutReversed' | 'hostFault' | 'internalError' | 'canceled' | 'notAbortable' | 'noStatement' | 'technicalError' | 'unknown';
|
|
57
|
+
/** Der Satz fuer den Bediener je Grund, deutsch. */
|
|
58
|
+
export declare const HPS_REASON_HINTS: Readonly<Record<HpsCodeReason, string>>;
|
|
59
|
+
/**
|
|
60
|
+
* Die beiden Gruende hinter einem Code mit `effect: 'hostUncertain'`: ob Geld
|
|
61
|
+
* geflossen ist, weiss das Terminal nicht.
|
|
62
|
+
*/
|
|
63
|
+
export declare function isHostUncertainReason(reason: HpsCodeReason | undefined): boolean;
|
|
64
|
+
/** Ein Ergebniscode, dessen Bedeutung feststeht (gemessen oder dokumentiert). */
|
|
30
65
|
export interface HpsMeasuredCode {
|
|
31
66
|
/** Der Ergebniscode, wie ihn das Terminal im Feld `responseCode` sendet. */
|
|
32
67
|
readonly code: string;
|
|
33
|
-
/** Bedeutung
|
|
68
|
+
/** Bedeutung — deutsch, ohne Umlaute (siehe Vorbild). */
|
|
34
69
|
readonly meaning: string;
|
|
35
70
|
/**
|
|
36
71
|
* `true`: der Code schreibt einen Ausgang fest (Teil der Positivliste,
|
|
37
|
-
* siehe [isConclusive]). `false`:
|
|
38
|
-
*
|
|
72
|
+
* siehe [isConclusive]). `false`: benannt, aber KEINE Aussage ueber den
|
|
73
|
+
* Vorgang -- oder ein ungewisser Host-Ausgang, siehe [HpsCode.effect].
|
|
39
74
|
*/
|
|
40
75
|
readonly conclusive: boolean;
|
|
41
76
|
}
|
|
77
|
+
/** Ein Eintrag der vollstaendigen Codetabelle [HPS_CODES]. */
|
|
78
|
+
export interface HpsCode extends HpsMeasuredCode {
|
|
79
|
+
/** Titel, wie hobex ihn fuehrt bzw. das Terminal als `responseText` sendet. */
|
|
80
|
+
readonly title: string;
|
|
81
|
+
readonly effect: HpsCodeEffect;
|
|
82
|
+
readonly reason: HpsCodeReason;
|
|
83
|
+
readonly source: HpsCodeSource;
|
|
84
|
+
/**
|
|
85
|
+
* Der Code weist die ANFRAGE selbst ab (TID, Form, Geraetezustand). Auf eine
|
|
86
|
+
* Zahlung ist das deren Ablehnung; auf eine STATUSABFRAGE heisst es nur, dass
|
|
87
|
+
* diese Abfrage nicht bedient wurde -- ueber den gesuchten Vorgang sagt es
|
|
88
|
+
* nichts (gemessen fuer `100108`). Siehe [isConclusiveAsStatus].
|
|
89
|
+
*/
|
|
90
|
+
readonly rejectsRequest: boolean;
|
|
91
|
+
}
|
|
42
92
|
/**
|
|
43
|
-
* Die
|
|
44
|
-
* `
|
|
45
|
-
*
|
|
93
|
+
* Die vollstaendige Codetabelle — Vertrag mit dem Dart-Zwilling
|
|
94
|
+
* (`HpsCodes.all` in `lib/src/hobex_hps/response_codes.dart`), ausgegeben als
|
|
95
|
+
* `fixtures/hobex-hps-codes.json`.
|
|
96
|
+
*
|
|
97
|
+
* Zwei Quellen: GEMESSEN an hobex-HPS-Geraeten (TID 3600335, HPS 1.10.0,
|
|
98
|
+
* Firmware 7.3.6, 26.–28.08.2026; TID 3556988 im Betrieb) und die
|
|
99
|
+
* Antwortcodeliste von hobex (erhalten 11.09.2026). Die Regel bleibt: nur ein
|
|
100
|
+
* Code mit feststehender Bedeutung schreibt einen Ausgang fest -- die Liste des
|
|
101
|
+
* Herstellers ist eine solche Feststellung, kein Raten aus der Codefamilie.
|
|
102
|
+
*
|
|
103
|
+
* Eingeordnet wird danach, WO im Ablauf ein dokumentierter Code entsteht:
|
|
104
|
+
* - vor dem Host (Anfrage, Karte, EMV-Kernel, Eingaben, Geraetezustand) ->
|
|
105
|
+
* `conclusive`, also `declined`;
|
|
106
|
+
* - `100029`, Zeitueberschreitung zum Host MIT auto-reversal -> ebenfalls
|
|
107
|
+
* `declined`, das Terminal storniert laut hobex selbst;
|
|
108
|
+
* - beim oder nach dem Host OHNE auto-reversal, dazu der Sammelcode `100999`
|
|
109
|
+
* -> `hostUncertain`.
|
|
46
110
|
*
|
|
47
|
-
* Reihenfolge
|
|
48
|
-
*
|
|
49
|
-
|
|
50
|
-
|
|
111
|
+
* Reihenfolge: zuerst die gemessenen wie im Messprotokoll, dann die
|
|
112
|
+
* dokumentierten aufsteigend -- identisch mit dem Dart-Zwilling.
|
|
113
|
+
*/
|
|
114
|
+
export declare const HPS_CODES: readonly HpsCode[];
|
|
115
|
+
/**
|
|
116
|
+
* @deprecated Seit 0.10.0 [HPS_CODES] -- die Tabelle fuehrt nicht mehr nur
|
|
117
|
+
* gemessene Codes. Gleicher Inhalt, bleibt fuer bestehende Aufrufer.
|
|
51
118
|
*/
|
|
52
119
|
export declare const HPS_MEASURED_CODES: readonly HpsMeasuredCode[];
|
|
53
120
|
/** `responseCode` einer genehmigten Zahlung. */
|
|
54
121
|
export declare const APPROVED_CODE = "0";
|
|
55
|
-
/** Siehe [
|
|
122
|
+
/** Siehe [HPS_CODES]: ungueltiger Vorgang, nichts passiert. */
|
|
56
123
|
export declare const INVALID_TRANSACTION_CODE = "9002";
|
|
57
|
-
/** Siehe [
|
|
124
|
+
/** Siehe [HPS_CODES]: aufgehoben. */
|
|
58
125
|
export declare const TRANSACTION_CANCELED_CODE = "9011";
|
|
59
|
-
/** Siehe [
|
|
126
|
+
/** Siehe [HPS_CODES]: keine Aussage. */
|
|
60
127
|
export declare const NO_STATEMENT_CODE = "9027";
|
|
61
|
-
/** Siehe [
|
|
128
|
+
/** Siehe [HPS_CODES]: Kennung nicht numerisch, keine Aussage. */
|
|
62
129
|
export declare const TECHNICAL_ERROR_CODE = "9900";
|
|
63
|
-
/** Siehe [
|
|
130
|
+
/** Siehe [HPS_CODES]: abgebrochen. */
|
|
64
131
|
export declare const ABORTED_CODE = "100002";
|
|
65
|
-
/** Siehe [
|
|
132
|
+
/** Siehe [HPS_CODES]: Karte nicht aufgelegt. */
|
|
66
133
|
export declare const CARD_NOT_PRESENT_CODE = "100003";
|
|
67
|
-
/** Siehe [
|
|
134
|
+
/** Siehe [HPS_CODES]: nicht mehr abbrechbar. */
|
|
68
135
|
export declare const NOT_ABORTABLE_CODE = "100010";
|
|
69
|
-
/** Siehe [
|
|
136
|
+
/** Siehe [HPS_CODES]: Betrag abgewiesen, vor dem Kartenfluss. */
|
|
70
137
|
export declare const INVALID_AMOUNT_CODE = "9003";
|
|
71
|
-
/** Siehe [
|
|
138
|
+
/** Siehe [HPS_CODES]: Betrag ausserhalb des zulaessigen Bereichs. */
|
|
72
139
|
export declare const AMOUNT_OUT_OF_RANGE_CODE = "100019";
|
|
73
|
-
/** Siehe [
|
|
140
|
+
/** Siehe [HPS_CODES]: Terminal-Kennung unbekannt. */
|
|
74
141
|
export declare const INVALID_TID_CODE = "100108";
|
|
75
142
|
/**
|
|
76
|
-
* Siehe [
|
|
143
|
+
* Siehe [HPS_CODES]: Host-Ablehnung, falsche PIN -- nichts belastet.
|
|
77
144
|
*
|
|
78
145
|
* Zweistellig, weil ein Antwortcode des HOSTS (ISO 8583, 55 = "Incorrect
|
|
79
146
|
* PIN"), kein `9xxx`-Terminalcode und kein `100xxx`-Code der HPS-Anwendung.
|
|
@@ -84,6 +151,58 @@ export declare const INVALID_TID_CODE = "100108";
|
|
|
84
151
|
* dann nicht 9027 antwortet, sondern mit dem Code selbst.
|
|
85
152
|
*/
|
|
86
153
|
export declare const WRONG_PIN_CODE = "55";
|
|
154
|
+
/** `100001` "Bad Request" -- nichts belastet. */
|
|
155
|
+
export declare const BAD_REQUEST_CODE = "100001";
|
|
156
|
+
/** `100004` "Card read failed" -- nichts belastet. Im Betrieb am 28.08.2026 gesehen. */
|
|
157
|
+
export declare const CARD_READ_FAILED_CODE = "100004";
|
|
158
|
+
/** `100005` "App select failed" -- nichts belastet. Im Betrieb am 28.08.2026 gesehen. */
|
|
159
|
+
export declare const APP_SELECT_FAILED_CODE = "100005";
|
|
160
|
+
/** `100006` "Communication with TecsXml failed" (No auto-reversal) -- ungewiss. */
|
|
161
|
+
export declare const HOST_COMMUNICATION_FAILED_CODE = "100006";
|
|
162
|
+
/** `100007` "Processing of TecsXml step failed" (No auto-reversal) -- ungewiss. */
|
|
163
|
+
export declare const HOST_STEP_FAILED_CODE = "100007";
|
|
164
|
+
/** `100008` "Invalid TID" laut hobex; gemessen wurde [INVALID_TID_CODE]. */
|
|
165
|
+
export declare const INVALID_TID_DOCUMENTED_CODE = "100008";
|
|
166
|
+
/** `100009` "Invalid Tx Type" -- nichts belastet. */
|
|
167
|
+
export declare const INVALID_TX_TYPE_CODE = "100009";
|
|
168
|
+
/** `100011` "Not Found" -- keine Aussage, aber ohne die Zwei-9027-Regel. */
|
|
169
|
+
export declare const NOT_FOUND_CODE = "100011";
|
|
170
|
+
/** `100012` "Max retries exceeded" -- nichts belastet. */
|
|
171
|
+
export declare const MAX_RETRIES_EXCEEDED_CODE = "100012";
|
|
172
|
+
/** `100013` "Diagnosis failed" -- nichts belastet. */
|
|
173
|
+
export declare const DIAGNOSIS_FAILED_CODE = "100013";
|
|
174
|
+
/** `100014` "Card information wasn't entered" (MOTO) -- nichts belastet. */
|
|
175
|
+
export declare const CARD_INFO_NOT_ENTERED_CODE = "100014";
|
|
176
|
+
/** `100015` "Card declined" (EMV-Kernel) -- nichts belastet. Im Betrieb am 28. und 31.08.2026 gesehen. */
|
|
177
|
+
export declare const CARD_DECLINED_CODE = "100015";
|
|
178
|
+
/** `100017` "Card Not Supported" -- nichts belastet. */
|
|
179
|
+
export declare const CARD_NOT_SUPPORTED_CODE = "100017";
|
|
180
|
+
/** `100018` "Scep enrollment failed" -- nichts belastet. */
|
|
181
|
+
export declare const SCEP_ENROLLMENT_FAILED_CODE = "100018";
|
|
182
|
+
/** `100020` "Refund password is invalid" -- nichts ausgezahlt. */
|
|
183
|
+
export declare const REFUND_PASSWORD_INVALID_CODE = "100020";
|
|
184
|
+
/** `100021` "Failed to enter the password" -- nichts ausgezahlt. */
|
|
185
|
+
export declare const PASSWORD_NOT_ENTERED_CODE = "100021";
|
|
186
|
+
/** `100022` "Terminal is blocked" -- nichts belastet. */
|
|
187
|
+
export declare const TERMINAL_BLOCKED_CODE = "100022";
|
|
188
|
+
/** `100023` "Invalid message type" -- ungewiss. */
|
|
189
|
+
export declare const INVALID_MESSAGE_TYPE_CODE = "100023";
|
|
190
|
+
/** `100024` "Transaction completion has failed" -- ungewiss. */
|
|
191
|
+
export declare const COMPLETION_FAILED_CODE = "100024";
|
|
192
|
+
/** `100025` "Refund transactions are disabled" -- nichts ausgezahlt. */
|
|
193
|
+
export declare const REFUND_DISABLED_CODE = "100025";
|
|
194
|
+
/** `100026` "Transaction was declined." (Chip-Daten fuer eine Karte ohne Chip) -- ungewiss. */
|
|
195
|
+
export declare const CHIP_DATA_MISMATCH_CODE = "100026";
|
|
196
|
+
/** `100027` "Unsupported UserData in TecsXml Response" -- ungewiss. */
|
|
197
|
+
export declare const UNSUPPORTED_USER_DATA_CODE = "100027";
|
|
198
|
+
/** `100028` "Tip selection process has failed." -- nichts belastet. */
|
|
199
|
+
export declare const TIP_SELECTION_FAILED_CODE = "100028";
|
|
200
|
+
/** `100029` "Communication with TecsXml timeout" (auto-reversal) -- nichts belastet. */
|
|
201
|
+
export declare const HOST_TIMEOUT_REVERSED_CODE = "100029";
|
|
202
|
+
/** `100998` "Terminal is busy" -- nichts belastet; gemessen als HTTP [TERMINAL_BUSY_HTTP_STATUS]. */
|
|
203
|
+
export declare const TERMINAL_BUSY_CODE = "100998";
|
|
204
|
+
/** `100999` "Internal Error" -- Sammelcode, ungewiss. */
|
|
205
|
+
export declare const INTERNAL_ERROR_CODE = "100999";
|
|
87
206
|
/**
|
|
88
207
|
* HTTP `409` ("Terminal is busy"): das Terminal serialisiert und weist eine
|
|
89
208
|
* zweite Anfrage ab, waehrend eine erste noch laeuft. Am 27.08.2026 gemessen:
|
|
@@ -91,12 +210,19 @@ export declare const WRONG_PIN_CODE = "55";
|
|
|
91
210
|
* Spur (die Statusabfrage auf seine Kennung liefert weiterhin
|
|
92
211
|
* [NO_STATEMENT_CODE]).
|
|
93
212
|
*
|
|
94
|
-
* Bewusst KEIN Eintrag in [
|
|
213
|
+
* Bewusst KEIN Eintrag in [HPS_CODES]: es ist ein HTTP-Status, kein
|
|
95
214
|
* `responseCode` — er entsteht, bevor ueberhaupt ein Antwortrumpf gelesen
|
|
96
215
|
* wird. Siehe `errors.ts` (`HpsConnectTerminalError.isTerminalBusy`) fuer die
|
|
97
216
|
* getrennte Auswertung.
|
|
98
217
|
*/
|
|
99
218
|
export declare const TERMINAL_BUSY_HTTP_STATUS = 409;
|
|
219
|
+
/** Der Eintrag zu [code] in [HPS_CODES], oder `undefined`, wenn seine Bedeutung nicht feststeht. */
|
|
220
|
+
export declare function hpsCodeInfo(code: string | undefined): HpsCode | undefined;
|
|
221
|
+
/**
|
|
222
|
+
* Der Grund zu [code] -- `'unknown'` fuer einen Code ausserhalb der Tabelle,
|
|
223
|
+
* `undefined` ohne Code.
|
|
224
|
+
*/
|
|
225
|
+
export declare function hpsCodeReason(code: string | undefined): HpsCodeReason | undefined;
|
|
100
226
|
/** Antwort des Terminals — Zahlung, Statusabfrage oder Abbruch. */
|
|
101
227
|
export interface HpsTransactionResponse {
|
|
102
228
|
/** Kennung dieser Transaktion, wie vom Terminal bestaetigt bzw. echoed. */
|
|
@@ -148,7 +274,13 @@ export declare function isApproved(res: Pick<HpsTransactionResponse, 'responseCo
|
|
|
148
274
|
export declare function isInProgress(res: Pick<HpsTransactionResponse, 'responseCode'>): boolean;
|
|
149
275
|
/** `true`, wenn ein Abbruch daran scheiterte, dass der Vorgang nicht mehr abbrechbar war. */
|
|
150
276
|
export declare function isNotAbortable(res: Pick<HpsTransactionResponse, 'responseCode'>): boolean;
|
|
151
|
-
/**
|
|
277
|
+
/**
|
|
278
|
+
* `true`, wenn das Terminal zu dieser Kennung keine Auskunft gibt (9027).
|
|
279
|
+
*
|
|
280
|
+
* Bewusst NUR `9027`, nicht auch [NOT_FOUND_CODE] (`100011`): auf `9027` ruht
|
|
281
|
+
* die Zwei-9027-Regel in `payments.ts`, und die ist fuer genau diesen Code
|
|
282
|
+
* gemessen. `100011` ist dokumentiert, aber nie gesehen.
|
|
283
|
+
*/
|
|
152
284
|
export declare function isNoStatement(res: Pick<HpsTransactionResponse, 'responseCode'>): boolean;
|
|
153
285
|
/** `true`, wenn das Terminal einen technischen Fehler meldet (9900). */
|
|
154
286
|
export declare function isTechnicalError(res: Pick<HpsTransactionResponse, 'responseCode'>): boolean;
|
|
@@ -163,13 +295,30 @@ export declare function isTechnicalError(res: Pick<HpsTransactionResponse, 'resp
|
|
|
163
295
|
export declare function isCanceled(res: Pick<HpsTransactionResponse, 'responseCode'>): boolean;
|
|
164
296
|
/**
|
|
165
297
|
* `true`, wenn diese Antwort ueberhaupt eine Aussage ueber den Ausgang
|
|
166
|
-
* traegt — ein Ergebniscode, der in [
|
|
167
|
-
*
|
|
298
|
+
* traegt — ein Ergebniscode, der in [HPS_CODES] als `conclusive` gefuehrt
|
|
299
|
+
* wird. Die einzige Stelle, an der ein Code zu einem Ausgang wird.
|
|
168
300
|
*/
|
|
169
301
|
export declare function isConclusive(res: Pick<HpsTransactionResponse, 'responseCode'>): boolean;
|
|
170
302
|
/**
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
303
|
+
* Wie [isConclusive], aber fuer die Antwort auf eine STATUSABFRAGE: ein Code,
|
|
304
|
+
* der die Anfrage selbst abweist (`rejectsRequest`, etwa `100022` "Terminal is
|
|
305
|
+
* blocked" oder `100108` "Invalid TID"), sagt dort nichts ueber den gesuchten
|
|
306
|
+
* Vorgang. Als `declined` gelesen, hiesse ein gesperrtes Terminal "die Zahlung
|
|
307
|
+
* ist nicht belastet".
|
|
308
|
+
*/
|
|
309
|
+
export declare function isConclusiveAsStatus(res: Pick<HpsTransactionResponse, 'responseCode'>): boolean;
|
|
310
|
+
/**
|
|
311
|
+
* `true`, wenn der Code einen Ausgang meldet, den das Terminal selbst nicht
|
|
312
|
+
* kennt: der hobex-Host war beteiligt, und das Terminal storniert nicht von
|
|
313
|
+
* sich aus (`effect: 'hostUncertain'`). Ein spaeteres `9027` auf die
|
|
314
|
+
* Statusabfrage heisst dann NICHT "nichts belastet" -- es spiegelt nur den
|
|
315
|
+
* Speicher des Terminals, nicht den des Hosts.
|
|
316
|
+
*/
|
|
317
|
+
export declare function isHostUncertain(res: Pick<HpsTransactionResponse, 'responseCode'>): boolean;
|
|
318
|
+
/**
|
|
319
|
+
* `true`, wenn ein Ergebniscode VORHANDEN ist, dessen Bedeutung aber nicht
|
|
320
|
+
* feststeht -- er fehlt in [HPS_CODES]. Ein Code, den dieses Modell schlicht
|
|
321
|
+
* nicht kennt; anders als [isNoStatement], [isTechnicalError] und
|
|
322
|
+
* [isHostUncertain], die eine Wissensluecke ueber den VORGANG benennen.
|
|
174
323
|
*/
|
|
175
324
|
export declare function isUnknownCode(res: Pick<HpsTransactionResponse, 'responseCode'>): boolean;
|