@kreiseck/kasseneck-api 0.7.0 → 0.7.2
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 +32 -0
- package/README.md +87 -15
- package/dist/cjs/client/aufrufe.d.ts +1 -1
- package/dist/cjs/client/aufrufe.js +1 -0
- package/dist/cjs/client/errors.d.ts +8 -4
- package/dist/cjs/client/errors.js +12 -9
- package/dist/cjs/client/receipts.d.ts +22 -0
- package/dist/cjs/client/receipts.js +16 -0
- package/dist/cjs/client/transport.js +5 -4
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +4 -2
- package/dist/cjs/models/cancellation.d.ts +28 -0
- package/dist/cjs/models/cancellation.js +31 -1
- package/dist/cjs/models/hobex-receipt.js +9 -2
- package/dist/cjs/models/index.d.ts +1 -1
- package/dist/cjs/models/index.js +3 -1
- package/dist/cjs/models/receipt-summary.d.ts +2 -0
- package/dist/cjs/models/receipt-summary.js +4 -1
- package/dist/cjs/models/receipt.js +8 -1
- package/dist/cjs/models/voucher.js +18 -2
- package/dist/cjs/payments/hobex-hps/connect-client.d.ts +104 -0
- package/dist/cjs/payments/hobex-hps/connect-client.js +159 -0
- package/dist/cjs/payments/hobex-hps/errors.d.ts +122 -0
- package/dist/cjs/payments/hobex-hps/errors.js +158 -0
- package/dist/cjs/payments/hobex-hps/events.d.ts +22 -0
- package/dist/cjs/payments/hobex-hps/events.js +2 -0
- package/dist/cjs/payments/hobex-hps/index.d.ts +27 -0
- package/dist/cjs/payments/hobex-hps/index.js +67 -0
- package/dist/cjs/payments/hobex-hps/outcome.d.ts +46 -0
- package/dist/cjs/payments/hobex-hps/outcome.js +7 -0
- package/dist/cjs/payments/hobex-hps/payments.d.ts +149 -0
- package/dist/cjs/payments/hobex-hps/payments.js +573 -0
- package/dist/cjs/payments/hobex-hps/receipt.d.ts +28 -0
- package/dist/cjs/payments/hobex-hps/receipt.js +60 -0
- package/dist/cjs/payments/hobex-hps/transaction-id.d.ts +65 -0
- package/dist/cjs/payments/hobex-hps/transaction-id.js +91 -0
- package/dist/cjs/payments/hobex-hps/transaction-response.d.ts +175 -0
- package/dist/cjs/payments/hobex-hps/transaction-response.js +266 -0
- package/dist/cjs/payments/hobex.js +9 -6
- package/dist/cjs/payments/index.d.ts +26 -14
- package/dist/cjs/payments/index.js +59 -15
- package/dist/cjs/printing/index.d.ts +1 -1
- package/dist/cjs/printing/index.js +2 -1
- package/dist/cjs/printing/webusb.d.ts +37 -7
- package/dist/cjs/printing/webusb.js +76 -18
- package/dist/cjs/receipt/epos.d.ts +18 -0
- package/dist/cjs/receipt/epos.js +78 -6
- package/dist/cjs/receipt/index.d.ts +1 -1
- package/dist/cjs/receipt/index.js +2 -1
- package/dist/cjs/receipt/layout.js +19 -0
- package/dist/cjs/register/index.d.ts +1 -1
- package/dist/cjs/register/index.js +2 -1
- package/dist/cjs/register/pairing.d.ts +59 -0
- package/dist/cjs/register/pairing.js +51 -2
- package/dist/esm/client/aufrufe.d.ts +1 -1
- package/dist/esm/client/aufrufe.js +1 -0
- package/dist/esm/client/errors.d.ts +8 -4
- package/dist/esm/client/errors.js +12 -9
- package/dist/esm/client/receipts.d.ts +22 -0
- package/dist/esm/client/receipts.js +16 -0
- package/dist/esm/client/transport.js +5 -4
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/models/cancellation.d.ts +28 -0
- package/dist/esm/models/cancellation.js +29 -0
- package/dist/esm/models/hobex-receipt.js +10 -3
- package/dist/esm/models/index.d.ts +1 -1
- package/dist/esm/models/index.js +1 -1
- package/dist/esm/models/receipt-summary.d.ts +2 -0
- package/dist/esm/models/receipt-summary.js +4 -1
- package/dist/esm/models/receipt.js +8 -1
- package/dist/esm/models/voucher.js +18 -2
- package/dist/esm/payments/hobex-hps/connect-client.d.ts +104 -0
- package/dist/esm/payments/hobex-hps/connect-client.js +156 -0
- package/dist/esm/payments/hobex-hps/errors.d.ts +122 -0
- package/dist/esm/payments/hobex-hps/errors.js +149 -0
- package/dist/esm/payments/hobex-hps/events.d.ts +22 -0
- package/dist/esm/payments/hobex-hps/events.js +1 -0
- package/dist/esm/payments/hobex-hps/index.d.ts +27 -0
- package/dist/esm/payments/hobex-hps/index.js +26 -0
- package/dist/esm/payments/hobex-hps/outcome.d.ts +46 -0
- package/dist/esm/payments/hobex-hps/outcome.js +4 -0
- package/dist/esm/payments/hobex-hps/payments.d.ts +149 -0
- package/dist/esm/payments/hobex-hps/payments.js +570 -0
- package/dist/esm/payments/hobex-hps/receipt.d.ts +28 -0
- package/dist/esm/payments/hobex-hps/receipt.js +57 -0
- package/dist/esm/payments/hobex-hps/transaction-id.d.ts +65 -0
- package/dist/esm/payments/hobex-hps/transaction-id.js +86 -0
- package/dist/esm/payments/hobex-hps/transaction-response.d.ts +175 -0
- package/dist/esm/payments/hobex-hps/transaction-response.js +254 -0
- package/dist/esm/payments/hobex.js +9 -6
- package/dist/esm/payments/index.d.ts +26 -14
- package/dist/esm/payments/index.js +26 -14
- package/dist/esm/printing/index.d.ts +1 -1
- package/dist/esm/printing/index.js +1 -1
- package/dist/esm/printing/webusb.d.ts +37 -7
- package/dist/esm/printing/webusb.js +74 -17
- package/dist/esm/receipt/epos.d.ts +18 -0
- package/dist/esm/receipt/epos.js +76 -6
- package/dist/esm/receipt/index.d.ts +1 -1
- package/dist/esm/receipt/index.js +1 -1
- package/dist/esm/receipt/layout.js +19 -0
- package/dist/esm/register/index.d.ts +1 -1
- package/dist/esm/register/index.js +1 -1
- package/dist/esm/register/pairing.d.ts +59 -0
- package/dist/esm/register/pairing.js +50 -2
- package/fixtures/belege/storno-rabatt.json +3 -2
- package/fixtures/belege/storno-teil.json +2 -1
- package/fixtures/belege/storno-voll.json +2 -1
- package/fixtures/erwartet/storno-rabatt.grid32.txt +1 -0
- package/fixtures/erwartet/storno-rabatt.grid48.txt +1 -0
- package/fixtures/erwartet/storno-rabatt.lines.json +6 -0
- package/fixtures/erwartet/storno-teil.grid32.txt +1 -0
- package/fixtures/erwartet/storno-teil.grid48.txt +1 -0
- package/fixtures/erwartet/storno-teil.lines.json +6 -0
- package/fixtures/erwartet/storno-voll.grid32.txt +1 -0
- package/fixtures/erwartet/storno-voll.grid48.txt +1 -0
- package/fixtures/erwartet/storno-voll.lines.json +6 -0
- package/fixtures/hobex-hps-codes.json +83 -0
- package/fixtures/manifest.json +12 -12
- package/fixtures/oberflaeche.json +2 -1
- package/package.json +3 -2
|
@@ -1,28 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Unterpfad `@kreiseck/kasseneck-api/payments` — die Zahlungswege, die ein
|
|
3
3
|
* Browser oder ein Node-Prozess wirklich gehen kann: **Stripe-Zahlungslinks**
|
|
4
|
-
* (Fernzahlung per Link/QR-Code)
|
|
5
|
-
* ueber ein bei Hobex registriertes Terminal, gesteuert ueber das Netz)
|
|
4
|
+
* (Fernzahlung per Link/QR-Code), die **Hobex-Cloud-API** (Kartenzahlung
|
|
5
|
+
* ueber ein bei Hobex registriertes Terminal, gesteuert ueber das Netz) und
|
|
6
|
+
* **Hobex HPS ueber Kasseneck Connect** (`./hobex-hps.js`) — ein physisches
|
|
7
|
+
* Terminal im Kassen-Netz, angesprochen ueber den lokalen Geraete-Agenten.
|
|
6
8
|
*
|
|
7
9
|
* **Was hier bewusst fehlt — und warum es auch nicht nachgeruestet wird:**
|
|
8
10
|
*
|
|
9
|
-
* - **Hobex HPS** spricht **lokal ueber TCP** mit einem angeschlossenen
|
|
10
|
-
* Terminal (roher Socket auf eine Geraete-IP im selben Netz).
|
|
11
11
|
* - **myPOS** und **SumUp** sind **Android-SDKs**; sie laufen als
|
|
12
12
|
* Bibliothek in einer Android-App und reden ueber Bluetooth bzw. das
|
|
13
|
-
* Hersteller-Geraet mit dem Terminal.
|
|
13
|
+
* Hersteller-Geraet mit dem Terminal. Ein Browser hat keine
|
|
14
|
+
* Android-Laufzeit — das ist keine Luecke in diesem Paket und auch nichts,
|
|
15
|
+
* was ein Buendler, ein Polyfill oder WebAssembly aufloest.
|
|
14
16
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* **Frueherer Stand, ueberholt:** hier stand einmal, Hobex HPS sei mangels
|
|
18
|
+
* roher TCP-Sockets im Browser unerreichbar. Das galt fuer den DIREKTEN
|
|
19
|
+
* Terminal-Kontakt (Zwilling: `HpsClient` in `kasseneck_api`) und gilt dafuer
|
|
20
|
+
* weiterhin — aber **Kasseneck Connect** ist ein lokaler Geraete-Agent, der
|
|
21
|
+
* ueber gewoehnliches HTTP erreichbar ist und **fuer** die Kasse mit dem
|
|
22
|
+
* Terminal spricht. Das ist kein Widerspruch zur Umgebungsgrenze, sondern ein
|
|
23
|
+
* zweiter, seit `hobex-hps.js` genutzter Weg um sie herum.
|
|
24
|
+
*
|
|
25
|
+
* Wer Gutschrift oder Storno am HPS-Terminal braucht, braucht weiterhin die
|
|
26
|
+
* Flutter-App: Connect exponiert dafuer (noch) keinen Endpunkt, siehe
|
|
27
|
+
* `hobex-hps/connect-client.ts`.
|
|
20
28
|
*
|
|
21
29
|
* **Kassen-Benutzer-Weg (`registerUserAuth`, Browser-Kasse):** **Keiner** der
|
|
22
|
-
* vier Zahlungs-Endpunkte setzt `allowRegisterUser`;
|
|
23
|
-
* `checkRequest(req, 'user', …)` und damit nur mit
|
|
24
|
-
* bildet das **nicht** nach — wer darf, entscheidet
|
|
25
|
-
* Hinweis steht **hier** und gilt fuer
|
|
30
|
+
* vier Cloud-Zahlungs-Endpunkte (Stripe, Hobex-Cloud) setzt `allowRegisterUser`;
|
|
31
|
+
* sie laufen alle ueber `checkRequest(req, 'user', …)` und damit nur mit
|
|
32
|
+
* `apiKeyAuth`. Dieses Paket bildet das **nicht** nach — wer darf, entscheidet
|
|
33
|
+
* allein das Backend. Der Hinweis steht **hier** und gilt fuer die beiden
|
|
34
|
+
* Cloud-Dateien dieses Unterpfads; `hobex-hps.js` spricht kein Kasseneck-Backend
|
|
35
|
+
* und kennt diese Unterscheidung nicht — dort entscheidet allein der
|
|
36
|
+
* Kopplungstoken von Kasseneck Connect.
|
|
26
37
|
*
|
|
27
38
|
* Welche **anderen** Endpunkte den Weg offen haben, steht bewusst nirgends in
|
|
28
39
|
* diesem Paket: eine abgeschriebene Liste veraltet still, und sie hat hier
|
|
@@ -31,3 +42,4 @@
|
|
|
31
42
|
export { StripeLinkMode, type StripeLinkModeKey } from '../enums/index.js';
|
|
32
43
|
export { type CreateStripeLinkOptions, type StripeCaptureResult, createStripeLink, stripeCaptureIntent, } from './stripe.js';
|
|
33
44
|
export { type HobexPayOptions, type HobexRefundOptions, type HobexTransactionIdOptions, hobexPay, hobexRefund, newHobexTransactionId, } from './hobex.js';
|
|
45
|
+
export { type CardPaymentOutcome, type HpsConnectClient, type HpsConnectClientOptions, type HpsConnectFetch, type HpsConnectFetchResponse, type HpsConnectPaymentOptions, type HpsConnectTarget, type HpsConnectTransactionOptions, type HpsMeasuredCode, type HpsPaymentEvent, type HpsPaymentEventKind, type HpsPaymentObserver, type HpsPaymentOptions, type HpsPayments, type HpsPaymentResult, type HpsPaymentsOptions, type HpsTransactionIdGeneratorOptions, type HpsTransactionResponse, ABORTED_CODE, APPROVED_CODE, CARD_NOT_PRESENT_CODE, createHpsConnectClient, createHpsPayments, createHpsTransactionIdGenerator, HPS_MEASURED_CODES, HpsClarifyTimeoutError, HpsConnectException, HpsConnectTerminalError, HpsConnectTransportError, HpsPreflightError, HpsTransactionIdError, INVALID_TRANSACTION_CODE, isApproved, isConclusive, isInProgress, isNoStatement, isNotAbortable, isTechnicalError, isUnknownCode, isValidHpsTransactionId, mayRetrySafely, MAX_TRANSACTION_ID_LENGTH, newHpsTransactionId, NOT_ABORTABLE_CODE, NO_STATEMENT_CODE, parseHpsTransactionResponse, PREFLIGHT_CONNECT_CODES, TECHNICAL_ERROR_CODE, TERMINAL_BUSY_HTTP_STATUS, TRANSACTION_CANCELED_CODE, } from './hobex-hps/index.js';
|
|
@@ -2,35 +2,46 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Unterpfad `@kreiseck/kasseneck-api/payments` — die Zahlungswege, die ein
|
|
4
4
|
* Browser oder ein Node-Prozess wirklich gehen kann: **Stripe-Zahlungslinks**
|
|
5
|
-
* (Fernzahlung per Link/QR-Code)
|
|
6
|
-
* ueber ein bei Hobex registriertes Terminal, gesteuert ueber das Netz)
|
|
5
|
+
* (Fernzahlung per Link/QR-Code), die **Hobex-Cloud-API** (Kartenzahlung
|
|
6
|
+
* ueber ein bei Hobex registriertes Terminal, gesteuert ueber das Netz) und
|
|
7
|
+
* **Hobex HPS ueber Kasseneck Connect** (`./hobex-hps.js`) — ein physisches
|
|
8
|
+
* Terminal im Kassen-Netz, angesprochen ueber den lokalen Geraete-Agenten.
|
|
7
9
|
*
|
|
8
10
|
* **Was hier bewusst fehlt — und warum es auch nicht nachgeruestet wird:**
|
|
9
11
|
*
|
|
10
|
-
* - **Hobex HPS** spricht **lokal ueber TCP** mit einem angeschlossenen
|
|
11
|
-
* Terminal (roher Socket auf eine Geraete-IP im selben Netz).
|
|
12
12
|
* - **myPOS** und **SumUp** sind **Android-SDKs**; sie laufen als
|
|
13
13
|
* Bibliothek in einer Android-App und reden ueber Bluetooth bzw. das
|
|
14
|
-
* Hersteller-Geraet mit dem Terminal.
|
|
14
|
+
* Hersteller-Geraet mit dem Terminal. Ein Browser hat keine
|
|
15
|
+
* Android-Laufzeit — das ist keine Luecke in diesem Paket und auch nichts,
|
|
16
|
+
* was ein Buendler, ein Polyfill oder WebAssembly aufloest.
|
|
15
17
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* **Frueherer Stand, ueberholt:** hier stand einmal, Hobex HPS sei mangels
|
|
19
|
+
* roher TCP-Sockets im Browser unerreichbar. Das galt fuer den DIREKTEN
|
|
20
|
+
* Terminal-Kontakt (Zwilling: `HpsClient` in `kasseneck_api`) und gilt dafuer
|
|
21
|
+
* weiterhin — aber **Kasseneck Connect** ist ein lokaler Geraete-Agent, der
|
|
22
|
+
* ueber gewoehnliches HTTP erreichbar ist und **fuer** die Kasse mit dem
|
|
23
|
+
* Terminal spricht. Das ist kein Widerspruch zur Umgebungsgrenze, sondern ein
|
|
24
|
+
* zweiter, seit `hobex-hps.js` genutzter Weg um sie herum.
|
|
25
|
+
*
|
|
26
|
+
* Wer Gutschrift oder Storno am HPS-Terminal braucht, braucht weiterhin die
|
|
27
|
+
* Flutter-App: Connect exponiert dafuer (noch) keinen Endpunkt, siehe
|
|
28
|
+
* `hobex-hps/connect-client.ts`.
|
|
21
29
|
*
|
|
22
30
|
* **Kassen-Benutzer-Weg (`registerUserAuth`, Browser-Kasse):** **Keiner** der
|
|
23
|
-
* vier Zahlungs-Endpunkte setzt `allowRegisterUser`;
|
|
24
|
-
* `checkRequest(req, 'user', …)` und damit nur mit
|
|
25
|
-
* bildet das **nicht** nach — wer darf, entscheidet
|
|
26
|
-
* Hinweis steht **hier** und gilt fuer
|
|
31
|
+
* vier Cloud-Zahlungs-Endpunkte (Stripe, Hobex-Cloud) setzt `allowRegisterUser`;
|
|
32
|
+
* sie laufen alle ueber `checkRequest(req, 'user', …)` und damit nur mit
|
|
33
|
+
* `apiKeyAuth`. Dieses Paket bildet das **nicht** nach — wer darf, entscheidet
|
|
34
|
+
* allein das Backend. Der Hinweis steht **hier** und gilt fuer die beiden
|
|
35
|
+
* Cloud-Dateien dieses Unterpfads; `hobex-hps.js` spricht kein Kasseneck-Backend
|
|
36
|
+
* und kennt diese Unterscheidung nicht — dort entscheidet allein der
|
|
37
|
+
* Kopplungstoken von Kasseneck Connect.
|
|
27
38
|
*
|
|
28
39
|
* Welche **anderen** Endpunkte den Weg offen haben, steht bewusst nirgends in
|
|
29
40
|
* diesem Paket: eine abgeschriebene Liste veraltet still, und sie hat hier
|
|
30
41
|
* nichts zu entscheiden.
|
|
31
42
|
*/
|
|
32
43
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
-
exports.newHobexTransactionId = exports.hobexRefund = exports.hobexPay = exports.stripeCaptureIntent = exports.createStripeLink = exports.StripeLinkMode = void 0;
|
|
44
|
+
exports.TRANSACTION_CANCELED_CODE = exports.TERMINAL_BUSY_HTTP_STATUS = exports.TECHNICAL_ERROR_CODE = exports.PREFLIGHT_CONNECT_CODES = exports.parseHpsTransactionResponse = exports.NO_STATEMENT_CODE = exports.NOT_ABORTABLE_CODE = exports.newHpsTransactionId = exports.MAX_TRANSACTION_ID_LENGTH = exports.mayRetrySafely = exports.isValidHpsTransactionId = exports.isUnknownCode = exports.isTechnicalError = exports.isNotAbortable = exports.isNoStatement = exports.isInProgress = exports.isConclusive = exports.isApproved = exports.INVALID_TRANSACTION_CODE = exports.HpsTransactionIdError = exports.HpsPreflightError = exports.HpsConnectTransportError = exports.HpsConnectTerminalError = exports.HpsConnectException = exports.HpsClarifyTimeoutError = exports.HPS_MEASURED_CODES = exports.createHpsTransactionIdGenerator = exports.createHpsPayments = exports.createHpsConnectClient = exports.CARD_NOT_PRESENT_CODE = exports.APPROVED_CODE = exports.ABORTED_CODE = exports.newHobexTransactionId = exports.hobexRefund = exports.hobexPay = exports.stripeCaptureIntent = exports.createStripeLink = exports.StripeLinkMode = void 0;
|
|
34
45
|
var index_js_1 = require("../enums/index.js");
|
|
35
46
|
Object.defineProperty(exports, "StripeLinkMode", { enumerable: true, get: function () { return index_js_1.StripeLinkMode; } });
|
|
36
47
|
var stripe_js_1 = require("./stripe.js");
|
|
@@ -40,3 +51,36 @@ var hobex_js_1 = require("./hobex.js");
|
|
|
40
51
|
Object.defineProperty(exports, "hobexPay", { enumerable: true, get: function () { return hobex_js_1.hobexPay; } });
|
|
41
52
|
Object.defineProperty(exports, "hobexRefund", { enumerable: true, get: function () { return hobex_js_1.hobexRefund; } });
|
|
42
53
|
Object.defineProperty(exports, "newHobexTransactionId", { enumerable: true, get: function () { return hobex_js_1.newHobexTransactionId; } });
|
|
54
|
+
var index_js_2 = require("./hobex-hps/index.js");
|
|
55
|
+
Object.defineProperty(exports, "ABORTED_CODE", { enumerable: true, get: function () { return index_js_2.ABORTED_CODE; } });
|
|
56
|
+
Object.defineProperty(exports, "APPROVED_CODE", { enumerable: true, get: function () { return index_js_2.APPROVED_CODE; } });
|
|
57
|
+
Object.defineProperty(exports, "CARD_NOT_PRESENT_CODE", { enumerable: true, get: function () { return index_js_2.CARD_NOT_PRESENT_CODE; } });
|
|
58
|
+
Object.defineProperty(exports, "createHpsConnectClient", { enumerable: true, get: function () { return index_js_2.createHpsConnectClient; } });
|
|
59
|
+
Object.defineProperty(exports, "createHpsPayments", { enumerable: true, get: function () { return index_js_2.createHpsPayments; } });
|
|
60
|
+
Object.defineProperty(exports, "createHpsTransactionIdGenerator", { enumerable: true, get: function () { return index_js_2.createHpsTransactionIdGenerator; } });
|
|
61
|
+
Object.defineProperty(exports, "HPS_MEASURED_CODES", { enumerable: true, get: function () { return index_js_2.HPS_MEASURED_CODES; } });
|
|
62
|
+
Object.defineProperty(exports, "HpsClarifyTimeoutError", { enumerable: true, get: function () { return index_js_2.HpsClarifyTimeoutError; } });
|
|
63
|
+
Object.defineProperty(exports, "HpsConnectException", { enumerable: true, get: function () { return index_js_2.HpsConnectException; } });
|
|
64
|
+
Object.defineProperty(exports, "HpsConnectTerminalError", { enumerable: true, get: function () { return index_js_2.HpsConnectTerminalError; } });
|
|
65
|
+
Object.defineProperty(exports, "HpsConnectTransportError", { enumerable: true, get: function () { return index_js_2.HpsConnectTransportError; } });
|
|
66
|
+
Object.defineProperty(exports, "HpsPreflightError", { enumerable: true, get: function () { return index_js_2.HpsPreflightError; } });
|
|
67
|
+
Object.defineProperty(exports, "HpsTransactionIdError", { enumerable: true, get: function () { return index_js_2.HpsTransactionIdError; } });
|
|
68
|
+
Object.defineProperty(exports, "INVALID_TRANSACTION_CODE", { enumerable: true, get: function () { return index_js_2.INVALID_TRANSACTION_CODE; } });
|
|
69
|
+
Object.defineProperty(exports, "isApproved", { enumerable: true, get: function () { return index_js_2.isApproved; } });
|
|
70
|
+
Object.defineProperty(exports, "isConclusive", { enumerable: true, get: function () { return index_js_2.isConclusive; } });
|
|
71
|
+
Object.defineProperty(exports, "isInProgress", { enumerable: true, get: function () { return index_js_2.isInProgress; } });
|
|
72
|
+
Object.defineProperty(exports, "isNoStatement", { enumerable: true, get: function () { return index_js_2.isNoStatement; } });
|
|
73
|
+
Object.defineProperty(exports, "isNotAbortable", { enumerable: true, get: function () { return index_js_2.isNotAbortable; } });
|
|
74
|
+
Object.defineProperty(exports, "isTechnicalError", { enumerable: true, get: function () { return index_js_2.isTechnicalError; } });
|
|
75
|
+
Object.defineProperty(exports, "isUnknownCode", { enumerable: true, get: function () { return index_js_2.isUnknownCode; } });
|
|
76
|
+
Object.defineProperty(exports, "isValidHpsTransactionId", { enumerable: true, get: function () { return index_js_2.isValidHpsTransactionId; } });
|
|
77
|
+
Object.defineProperty(exports, "mayRetrySafely", { enumerable: true, get: function () { return index_js_2.mayRetrySafely; } });
|
|
78
|
+
Object.defineProperty(exports, "MAX_TRANSACTION_ID_LENGTH", { enumerable: true, get: function () { return index_js_2.MAX_TRANSACTION_ID_LENGTH; } });
|
|
79
|
+
Object.defineProperty(exports, "newHpsTransactionId", { enumerable: true, get: function () { return index_js_2.newHpsTransactionId; } });
|
|
80
|
+
Object.defineProperty(exports, "NOT_ABORTABLE_CODE", { enumerable: true, get: function () { return index_js_2.NOT_ABORTABLE_CODE; } });
|
|
81
|
+
Object.defineProperty(exports, "NO_STATEMENT_CODE", { enumerable: true, get: function () { return index_js_2.NO_STATEMENT_CODE; } });
|
|
82
|
+
Object.defineProperty(exports, "parseHpsTransactionResponse", { enumerable: true, get: function () { return index_js_2.parseHpsTransactionResponse; } });
|
|
83
|
+
Object.defineProperty(exports, "PREFLIGHT_CONNECT_CODES", { enumerable: true, get: function () { return index_js_2.PREFLIGHT_CONNECT_CODES; } });
|
|
84
|
+
Object.defineProperty(exports, "TECHNICAL_ERROR_CODE", { enumerable: true, get: function () { return index_js_2.TECHNICAL_ERROR_CODE; } });
|
|
85
|
+
Object.defineProperty(exports, "TERMINAL_BUSY_HTTP_STATUS", { enumerable: true, get: function () { return index_js_2.TERMINAL_BUSY_HTTP_STATUS; } });
|
|
86
|
+
Object.defineProperty(exports, "TRANSACTION_CANCELED_CODE", { enumerable: true, get: function () { return index_js_2.TRANSACTION_CANCELED_CODE; } });
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { type PosPaperSize, type PosAlign, type PosFont, type PosCutMode, type PosCodeTable, type PosTextSize, type QrSize, type QrCorrection, type PosStyles, type PosColumn, type EscPosOptions, type EscPosTextOptions, type EscPosHrOptions, type EscPosQrOptions, type EscPosDocument, createEscPosDocument, escPosBytes, escPosReset, escPosSetGlobalCodeTable, escPosSetGlobalFont, escPosSetStyles, escPosText, escPosEmptyLines, escPosFeed, escPosCut, escPosHr, escPosRow, escPosQrCode, encodeEscPosText, qrCodeBytes, escPosMaxCharsPerLine, escPosWortzeilen, wortzeilenText, } from './escpos.js';
|
|
2
2
|
export { escPosPrintableText } from './printable.js';
|
|
3
|
-
export { type UsbEndpointLike, type UsbAlternateLike, type UsbInterfaceLike, type UsbConfigurationLike, type UsbTransferOutResultLike, type UsbWriterLike, type UsbIdentityLike, type UsbDeviceLike, type UsbPrinterEndpoint, type UsbPrinterConnection, USB_VENDOR_EPSON, USB_CLASS_PRINTER, usbDeviceKey, usbFindPrinterEndpoint, usbWriteAll, usbConnectPrinter, usbPrint, usbDisconnect, } from './webusb.js';
|
|
3
|
+
export { type UsbEndpointLike, type UsbAlternateLike, type UsbInterfaceLike, type UsbConfigurationLike, type UsbTransferOutResultLike, type UsbWriterLike, type UsbIdentityLike, type UsbDeviceLike, type UsbPrinterEndpoint, type UsbPrinterConnection, USB_VENDOR_EPSON, USB_CLASS_PRINTER, UsbTimeoutError, usbDeviceKey, usbFindPrinterEndpoint, usbWriteAll, usbConnectPrinter, usbPrint, usbDisconnect, } from './webusb.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.usbDisconnect = exports.usbPrint = exports.usbConnectPrinter = exports.usbWriteAll = exports.usbFindPrinterEndpoint = exports.usbDeviceKey = exports.USB_CLASS_PRINTER = exports.USB_VENDOR_EPSON = exports.escPosPrintableText = exports.wortzeilenText = exports.escPosWortzeilen = exports.escPosMaxCharsPerLine = exports.qrCodeBytes = exports.encodeEscPosText = exports.escPosQrCode = exports.escPosRow = exports.escPosHr = exports.escPosCut = exports.escPosFeed = exports.escPosEmptyLines = exports.escPosText = exports.escPosSetStyles = exports.escPosSetGlobalFont = exports.escPosSetGlobalCodeTable = exports.escPosReset = exports.escPosBytes = exports.createEscPosDocument = void 0;
|
|
3
|
+
exports.usbDisconnect = exports.usbPrint = exports.usbConnectPrinter = exports.usbWriteAll = exports.usbFindPrinterEndpoint = exports.usbDeviceKey = exports.UsbTimeoutError = exports.USB_CLASS_PRINTER = exports.USB_VENDOR_EPSON = exports.escPosPrintableText = exports.wortzeilenText = exports.escPosWortzeilen = exports.escPosMaxCharsPerLine = exports.qrCodeBytes = exports.encodeEscPosText = exports.escPosQrCode = exports.escPosRow = exports.escPosHr = exports.escPosCut = exports.escPosFeed = exports.escPosEmptyLines = exports.escPosText = exports.escPosSetStyles = exports.escPosSetGlobalFont = exports.escPosSetGlobalCodeTable = exports.escPosReset = exports.escPosBytes = exports.createEscPosDocument = void 0;
|
|
4
4
|
var escpos_js_1 = require("./escpos.js");
|
|
5
5
|
Object.defineProperty(exports, "createEscPosDocument", { enumerable: true, get: function () { return escpos_js_1.createEscPosDocument; } });
|
|
6
6
|
Object.defineProperty(exports, "escPosBytes", { enumerable: true, get: function () { return escpos_js_1.escPosBytes; } });
|
|
@@ -25,6 +25,7 @@ Object.defineProperty(exports, "escPosPrintableText", { enumerable: true, get: f
|
|
|
25
25
|
var webusb_js_1 = require("./webusb.js");
|
|
26
26
|
Object.defineProperty(exports, "USB_VENDOR_EPSON", { enumerable: true, get: function () { return webusb_js_1.USB_VENDOR_EPSON; } });
|
|
27
27
|
Object.defineProperty(exports, "USB_CLASS_PRINTER", { enumerable: true, get: function () { return webusb_js_1.USB_CLASS_PRINTER; } });
|
|
28
|
+
Object.defineProperty(exports, "UsbTimeoutError", { enumerable: true, get: function () { return webusb_js_1.UsbTimeoutError; } });
|
|
28
29
|
Object.defineProperty(exports, "usbDeviceKey", { enumerable: true, get: function () { return webusb_js_1.usbDeviceKey; } });
|
|
29
30
|
Object.defineProperty(exports, "usbFindPrinterEndpoint", { enumerable: true, get: function () { return webusb_js_1.usbFindPrinterEndpoint; } });
|
|
30
31
|
Object.defineProperty(exports, "usbWriteAll", { enumerable: true, get: function () { return webusb_js_1.usbWriteAll; } });
|
|
@@ -75,15 +75,45 @@ export declare function usbDeviceKey(d: UsbIdentityLike): string;
|
|
|
75
75
|
export declare function usbFindPrinterEndpoint(d: {
|
|
76
76
|
configuration: UsbConfigurationLike | null;
|
|
77
77
|
}): UsbPrinterEndpoint | null;
|
|
78
|
-
/**
|
|
79
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Ein USB-Schritt kam nicht innerhalb der Frist zurueck. Anders als bei einem
|
|
80
|
+
* HTTP-Aufruf (siehe `receipt/epos.ts`, `EposConnectionError`) kennt WebUSB
|
|
81
|
+
* fuer diese Methoden kein Abbruchsignal -- der zugrunde liegende Transfer
|
|
82
|
+
* kann am Geraet WEITERLAUFEN, auch nachdem dieser Fehler geworfen wurde. Was
|
|
83
|
+
* hier begrenzt wird, ist NUR das Warten dieses Aufrufers, nicht der Transfer
|
|
84
|
+
* selbst. Dieselbe ehrliche Einschraenkung wie beim Dart-Zwilling
|
|
85
|
+
* `HpsPayments` (`_abortBudget`-Kommentar): ein weicher Zeitablauf ist besser
|
|
86
|
+
* als gar keiner, aber kein echtes Abbrechen.
|
|
87
|
+
*/
|
|
88
|
+
export declare class UsbTimeoutError extends Error {
|
|
89
|
+
readonly name = "UsbTimeoutError";
|
|
90
|
+
readonly schritt: string;
|
|
91
|
+
readonly timeoutMs: number;
|
|
92
|
+
constructor(schritt: string, timeoutMs: number);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Bytes blockweise an den OUT-Endpunkt; liefert die geschriebene Gesamtzahl,
|
|
96
|
+
* wirft bei Fehlstatus. [timeoutMs] gilt JE Block, nicht fuer den gesamten
|
|
97
|
+
* Druckauftrag -- ein grosser Beleg darf laenger brauchen, ein EINZELNER
|
|
98
|
+
* haengender Block soll trotzdem auffallen, statt den ganzen Aufruf
|
|
99
|
+
* unbegrenzt festzuhalten (genau das Muster, das im Flutter-Paket einen
|
|
100
|
+
* Verkauf angehalten hat).
|
|
101
|
+
*/
|
|
102
|
+
export declare function usbWriteAll(dev: UsbWriterLike, endpointNumber: number, bytes: Uint8Array, blockSize?: number, timeoutMs?: number): Promise<number>;
|
|
80
103
|
/**
|
|
81
104
|
* Geraet oeffnen, Konfiguration waehlen, Druckerschnittstelle belegen. Wirft
|
|
82
105
|
* verstaendlich, wenn ein Treiber das Geraet haelt oder kein Drucker-Endpunkt
|
|
83
|
-
* da ist -- und schliesst das Geraet dann wieder.
|
|
106
|
+
* da ist -- und schliesst das Geraet dann wieder. Jeder Schritt steht unter
|
|
107
|
+
* [timeoutMs] (siehe [UsbTimeoutError]).
|
|
84
108
|
*/
|
|
85
|
-
export declare function usbConnectPrinter(device: UsbDeviceLike): Promise<UsbPrinterConnection>;
|
|
109
|
+
export declare function usbConnectPrinter(device: UsbDeviceLike, timeoutMs?: number): Promise<UsbPrinterConnection>;
|
|
86
110
|
/** Bytes an eine bestehende Verbindung. */
|
|
87
|
-
export declare function usbPrint(c: UsbPrinterConnection, bytes: Uint8Array): Promise<number>;
|
|
88
|
-
/**
|
|
89
|
-
|
|
111
|
+
export declare function usbPrint(c: UsbPrinterConnection, bytes: Uint8Array, timeoutMs?: number): Promise<number>;
|
|
112
|
+
/**
|
|
113
|
+
* Schnittstelle freigeben und schliessen; Fehler dabei sind egal (Geraet ist
|
|
114
|
+
* ohnehin weg) -- ABER ein haengender Aufruf ist etwas anderes als ein Fehler:
|
|
115
|
+
* ein `catch` faengt nur eine ABLEHNUNG ab, nicht ein Versprechen, das nie
|
|
116
|
+
* aufloest. Ohne die Frist haette ein steckengebliebenes `releaseInterface`
|
|
117
|
+
* `usbDisconnect` selbst unbegrenzt haengen lassen, trotz des `try/catch`.
|
|
118
|
+
*/
|
|
119
|
+
export declare function usbDisconnect(c: UsbPrinterConnection, timeoutMs?: number): Promise<void>;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* es ohne Browser testbar bleibt und in jeder App gleich laeuft.
|
|
11
11
|
*/
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.USB_CLASS_PRINTER = exports.USB_VENDOR_EPSON = void 0;
|
|
13
|
+
exports.UsbTimeoutError = exports.USB_CLASS_PRINTER = exports.USB_VENDOR_EPSON = void 0;
|
|
14
14
|
exports.usbDeviceKey = usbDeviceKey;
|
|
15
15
|
exports.usbFindPrinterEndpoint = usbFindPrinterEndpoint;
|
|
16
16
|
exports.usbWriteAll = usbWriteAll;
|
|
@@ -44,15 +44,58 @@ function usbFindPrinterEndpoint(d) {
|
|
|
44
44
|
kandidaten.sort((a, b) => a.rang - b.rang);
|
|
45
45
|
return kandidaten[0]?.e ?? null;
|
|
46
46
|
}
|
|
47
|
-
/**
|
|
48
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Ein USB-Schritt kam nicht innerhalb der Frist zurueck. Anders als bei einem
|
|
49
|
+
* HTTP-Aufruf (siehe `receipt/epos.ts`, `EposConnectionError`) kennt WebUSB
|
|
50
|
+
* fuer diese Methoden kein Abbruchsignal -- der zugrunde liegende Transfer
|
|
51
|
+
* kann am Geraet WEITERLAUFEN, auch nachdem dieser Fehler geworfen wurde. Was
|
|
52
|
+
* hier begrenzt wird, ist NUR das Warten dieses Aufrufers, nicht der Transfer
|
|
53
|
+
* selbst. Dieselbe ehrliche Einschraenkung wie beim Dart-Zwilling
|
|
54
|
+
* `HpsPayments` (`_abortBudget`-Kommentar): ein weicher Zeitablauf ist besser
|
|
55
|
+
* als gar keiner, aber kein echtes Abbrechen.
|
|
56
|
+
*/
|
|
57
|
+
class UsbTimeoutError extends Error {
|
|
58
|
+
name = 'UsbTimeoutError';
|
|
59
|
+
schritt;
|
|
60
|
+
timeoutMs;
|
|
61
|
+
constructor(schritt, timeoutMs) {
|
|
62
|
+
super(`USB-Drucker antwortet nicht (${schritt}, Zeitlimit ${timeoutMs} ms überschritten) — Kabel/Gerät prüfen.`);
|
|
63
|
+
this.schritt = schritt;
|
|
64
|
+
this.timeoutMs = timeoutMs;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.UsbTimeoutError = UsbTimeoutError;
|
|
68
|
+
/** Vorgabe-Zeitlimit je USB-Schritt. Ein einzelner Block/Schritt braucht Millisekunden; alles darueber ist ein haengendes Geraet. */
|
|
69
|
+
const USB_ZEITLIMIT_VORGABE_MS = 15000;
|
|
70
|
+
/** Begrenzt das WARTEN auf [promise] -- siehe [UsbTimeoutError] fuer die Einschraenkung. */
|
|
71
|
+
function mitZeitlimit(promise, ms, schritt) {
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
const timer = setTimeout(() => reject(new UsbTimeoutError(schritt, ms)), ms);
|
|
74
|
+
promise.then((v) => {
|
|
75
|
+
clearTimeout(timer);
|
|
76
|
+
resolve(v);
|
|
77
|
+
}, (e) => {
|
|
78
|
+
clearTimeout(timer);
|
|
79
|
+
reject(e);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Bytes blockweise an den OUT-Endpunkt; liefert die geschriebene Gesamtzahl,
|
|
85
|
+
* wirft bei Fehlstatus. [timeoutMs] gilt JE Block, nicht fuer den gesamten
|
|
86
|
+
* Druckauftrag -- ein grosser Beleg darf laenger brauchen, ein EINZELNER
|
|
87
|
+
* haengender Block soll trotzdem auffallen, statt den ganzen Aufruf
|
|
88
|
+
* unbegrenzt festzuhalten (genau das Muster, das im Flutter-Paket einen
|
|
89
|
+
* Verkauf angehalten hat).
|
|
90
|
+
*/
|
|
91
|
+
async function usbWriteAll(dev, endpointNumber, bytes, blockSize = 16384, timeoutMs = USB_ZEITLIMIT_VORGABE_MS) {
|
|
49
92
|
const groesse = Math.max(1, Math.floor(blockSize));
|
|
50
93
|
let n = 0;
|
|
51
94
|
for (let von = 0; von < bytes.length; von += groesse) {
|
|
52
95
|
// eigener ArrayBuffer je Block (BufferSource verlangt kein SharedArrayBuffer)
|
|
53
96
|
const block = new Uint8Array(Math.min(groesse, bytes.length - von));
|
|
54
97
|
block.set(bytes.subarray(von, von + block.length));
|
|
55
|
-
const r = await dev.transferOut(endpointNumber, block);
|
|
98
|
+
const r = await mitZeitlimit(dev.transferOut(endpointNumber, block), timeoutMs, 'transferOut');
|
|
56
99
|
if (r.status !== 'ok')
|
|
57
100
|
throw new Error(`USB-Übertragung: ${r.status} nach ${n} Byte`);
|
|
58
101
|
n += r.bytesWritten;
|
|
@@ -62,49 +105,64 @@ async function usbWriteAll(dev, endpointNumber, bytes, blockSize = 16384) {
|
|
|
62
105
|
/**
|
|
63
106
|
* Geraet oeffnen, Konfiguration waehlen, Druckerschnittstelle belegen. Wirft
|
|
64
107
|
* verstaendlich, wenn ein Treiber das Geraet haelt oder kein Drucker-Endpunkt
|
|
65
|
-
* da ist -- und schliesst das Geraet dann wieder.
|
|
108
|
+
* da ist -- und schliesst das Geraet dann wieder. Jeder Schritt steht unter
|
|
109
|
+
* [timeoutMs] (siehe [UsbTimeoutError]).
|
|
66
110
|
*/
|
|
67
|
-
async function usbConnectPrinter(device) {
|
|
111
|
+
async function usbConnectPrinter(device, timeoutMs = USB_ZEITLIMIT_VORGABE_MS) {
|
|
68
112
|
if (!device.opened)
|
|
69
|
-
await device.open();
|
|
113
|
+
await mitZeitlimit(device.open(), timeoutMs, 'open');
|
|
70
114
|
try {
|
|
71
115
|
if (!device.configuration)
|
|
72
|
-
await device.selectConfiguration(1);
|
|
116
|
+
await mitZeitlimit(device.selectConfiguration(1), timeoutMs, 'selectConfiguration');
|
|
73
117
|
const ep = usbFindPrinterEndpoint(device);
|
|
74
118
|
if (!ep)
|
|
75
119
|
throw new Error('Kein Drucker-Endpunkt am USB-Gerät gefunden — ist das ein Bondrucker?');
|
|
76
120
|
try {
|
|
77
|
-
await device.claimInterface(ep.interfaceNumber);
|
|
121
|
+
await mitZeitlimit(device.claimInterface(ep.interfaceNumber), timeoutMs, 'claimInterface');
|
|
78
122
|
}
|
|
79
123
|
catch (e) {
|
|
124
|
+
// Ein Zeitablauf ist etwas anderes als ein abgelehnter Claim: Ersterer
|
|
125
|
+
// sagt "das Geraet antwortet gar nicht", Letzterer "ein Treiber haelt
|
|
126
|
+
// es". Beide unter derselben Meldung zu verstecken, waere dieselbe
|
|
127
|
+
// Verwechslung, die an anderer Stelle in diesem Vorhaben schon einmal
|
|
128
|
+
// Kartendaten falsch eingeordnet hat -- hier nur mit einem Drucker
|
|
129
|
+
// statt eines Terminals.
|
|
130
|
+
if (e instanceof UsbTimeoutError)
|
|
131
|
+
throw e;
|
|
80
132
|
const grund = e instanceof Error && e.message ? ` (${e.message})` : '';
|
|
81
133
|
throw new Error(`USB-Schnittstelle belegt${grund} — ein Treiber hält den Drucker. Windows: Epson-Treiber entfernen oder mit Zadig auf WinUSB umstellen.`);
|
|
82
134
|
}
|
|
83
135
|
if (ep.alternateSetting !== 0)
|
|
84
|
-
await device.selectAlternateInterface(ep.interfaceNumber, ep.alternateSetting);
|
|
136
|
+
await mitZeitlimit(device.selectAlternateInterface(ep.interfaceNumber, ep.alternateSetting), timeoutMs, 'selectAlternateInterface');
|
|
85
137
|
const name = [device.manufacturerName, device.productName].filter((t) => !!t).join(' ') || 'USB-Drucker';
|
|
86
138
|
return { device, name, interfaceNumber: ep.interfaceNumber, endpointNumber: ep.endpointNumber, key: usbDeviceKey(device) };
|
|
87
139
|
}
|
|
88
140
|
catch (e) {
|
|
89
141
|
try {
|
|
90
|
-
await device.close();
|
|
142
|
+
await mitZeitlimit(device.close(), timeoutMs, 'close');
|
|
91
143
|
}
|
|
92
|
-
catch { /* schon zu */ }
|
|
144
|
+
catch { /* schon zu, oder haengt ebenfalls -- egal, wir werfen ohnehin schon */ }
|
|
93
145
|
throw e;
|
|
94
146
|
}
|
|
95
147
|
}
|
|
96
148
|
/** Bytes an eine bestehende Verbindung. */
|
|
97
|
-
function usbPrint(c, bytes) {
|
|
98
|
-
return usbWriteAll(c.device, c.endpointNumber, bytes);
|
|
149
|
+
function usbPrint(c, bytes, timeoutMs = USB_ZEITLIMIT_VORGABE_MS) {
|
|
150
|
+
return usbWriteAll(c.device, c.endpointNumber, bytes, undefined, timeoutMs);
|
|
99
151
|
}
|
|
100
|
-
/**
|
|
101
|
-
|
|
152
|
+
/**
|
|
153
|
+
* Schnittstelle freigeben und schliessen; Fehler dabei sind egal (Geraet ist
|
|
154
|
+
* ohnehin weg) -- ABER ein haengender Aufruf ist etwas anderes als ein Fehler:
|
|
155
|
+
* ein `catch` faengt nur eine ABLEHNUNG ab, nicht ein Versprechen, das nie
|
|
156
|
+
* aufloest. Ohne die Frist haette ein steckengebliebenes `releaseInterface`
|
|
157
|
+
* `usbDisconnect` selbst unbegrenzt haengen lassen, trotz des `try/catch`.
|
|
158
|
+
*/
|
|
159
|
+
async function usbDisconnect(c, timeoutMs = USB_ZEITLIMIT_VORGABE_MS) {
|
|
102
160
|
try {
|
|
103
|
-
await c.device.releaseInterface(c.interfaceNumber);
|
|
161
|
+
await mitZeitlimit(c.device.releaseInterface(c.interfaceNumber), timeoutMs, 'releaseInterface');
|
|
104
162
|
}
|
|
105
163
|
catch { /* egal */ }
|
|
106
164
|
try {
|
|
107
|
-
await c.device.close();
|
|
165
|
+
await mitZeitlimit(c.device.close(), timeoutMs, 'close');
|
|
108
166
|
}
|
|
109
167
|
catch { /* egal */ }
|
|
110
168
|
}
|
|
@@ -47,6 +47,24 @@ export interface EposResponse {
|
|
|
47
47
|
export declare function eposServiceUrl(ip: string, devid?: string, timeoutMs?: number): string;
|
|
48
48
|
export declare function eposSoapEnvelope(innerXml: string): string;
|
|
49
49
|
export declare function eposParseResponse(text: string): EposResponse;
|
|
50
|
+
/**
|
|
51
|
+
* Ob ein Aufruf an [eposDirectSend] an einem ZEITABLAUF scheiterte oder an
|
|
52
|
+
* einer sonst abgelehnten/nie zustande gekommenen Verbindung -- ein Aufrufer
|
|
53
|
+
* muss das unterscheiden koennen. Ein Zeitablauf heisst "der Drucker koennte
|
|
54
|
+
* noch antworten, spaeter nochmal versuchen"; eine Ablehnung heisst "unter
|
|
55
|
+
* dieser Adresse ist niemand" (falsche IP, Kabel raus, Zertifikat nicht
|
|
56
|
+
* akzeptiert). Vor dieser Klasse trug die eine Fehlermeldung fuer beide
|
|
57
|
+
* Faelle keine maschinenlesbare Unterscheidung -- ein Aufrufer haette sie nur
|
|
58
|
+
* am Text erraten koennen, und genau diese Art von Kopplung an einen Text hat
|
|
59
|
+
* sich an anderer Stelle in diesem Vorhaben schon als brueckig erwiesen.
|
|
60
|
+
*/
|
|
61
|
+
export declare class EposConnectionError extends Error {
|
|
62
|
+
readonly name = "EposConnectionError";
|
|
63
|
+
readonly ip: string;
|
|
64
|
+
/** `true`, wenn das Zeitlimit ablief, BEVOR eine Antwort da war. */
|
|
65
|
+
readonly timedOut: boolean;
|
|
66
|
+
constructor(ip: string, timedOut: boolean);
|
|
67
|
+
}
|
|
50
68
|
/** Beleg direkt drucken; wirft bei Netz-/Zertifikatsproblemen, sonst die Drucker-Antwort. */
|
|
51
69
|
export declare function eposDirectPrint(layout: ReceiptLayout, o: EposDirectOptions, fetchFn?: typeof fetch): Promise<EposResponse>;
|
|
52
70
|
/** Verbindungstest: leeres Dokument, druckt nichts, liefert den Druckerstatus. */
|
package/dist/cjs/receipt/epos.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EposConnectionError = void 0;
|
|
3
4
|
exports.eposXmlEscape = eposXmlEscape;
|
|
4
5
|
exports.eposPrintXml = eposPrintXml;
|
|
5
6
|
exports.eposServiceUrl = eposServiceUrl;
|
|
@@ -70,19 +71,90 @@ function eposParseResponse(text) {
|
|
|
70
71
|
const attr = (n) => new RegExp(`\\b${n}="([^"]*)"`).exec(m[1] ?? '')?.[1] ?? '';
|
|
71
72
|
return { success: attr('success') === 'true', code: attr('code'), status: attr('status') };
|
|
72
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Ob ein Aufruf an [eposDirectSend] an einem ZEITABLAUF scheiterte oder an
|
|
76
|
+
* einer sonst abgelehnten/nie zustande gekommenen Verbindung -- ein Aufrufer
|
|
77
|
+
* muss das unterscheiden koennen. Ein Zeitablauf heisst "der Drucker koennte
|
|
78
|
+
* noch antworten, spaeter nochmal versuchen"; eine Ablehnung heisst "unter
|
|
79
|
+
* dieser Adresse ist niemand" (falsche IP, Kabel raus, Zertifikat nicht
|
|
80
|
+
* akzeptiert). Vor dieser Klasse trug die eine Fehlermeldung fuer beide
|
|
81
|
+
* Faelle keine maschinenlesbare Unterscheidung -- ein Aufrufer haette sie nur
|
|
82
|
+
* am Text erraten koennen, und genau diese Art von Kopplung an einen Text hat
|
|
83
|
+
* sich an anderer Stelle in diesem Vorhaben schon als brueckig erwiesen.
|
|
84
|
+
*/
|
|
85
|
+
class EposConnectionError extends Error {
|
|
86
|
+
name = 'EposConnectionError';
|
|
87
|
+
ip;
|
|
88
|
+
/** `true`, wenn das Zeitlimit ablief, BEVOR eine Antwort da war. */
|
|
89
|
+
timedOut;
|
|
90
|
+
constructor(ip, timedOut) {
|
|
91
|
+
const grund = timedOut ? 'antwortet nicht (Zeitlimit überschritten)' : 'nicht erreichbar';
|
|
92
|
+
super(`Drucker ${grund}. Einmal https://${ip.trim()} im Browser öffnen und das Zertifikat akzeptieren, ` +
|
|
93
|
+
'Zugriff aufs lokale Netz erlauben, ePOS-Print am Drucker auf Enable.');
|
|
94
|
+
this.ip = ip;
|
|
95
|
+
this.timedOut = timedOut;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.EposConnectionError = EposConnectionError;
|
|
99
|
+
/** Lehnt ab, sobald [signal] abbricht -- die Naht fuer die Frist in [eposDirectSend]. */
|
|
100
|
+
function alsAbbruchAbgelehnt(signal) {
|
|
101
|
+
return new Promise((_erfuellen, ablehnen) => {
|
|
102
|
+
if (signal.aborted) {
|
|
103
|
+
ablehnen(new Error('abgebrochen'));
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
signal.addEventListener('abort', () => ablehnen(new Error('abgebrochen')), { once: true });
|
|
107
|
+
});
|
|
108
|
+
}
|
|
73
109
|
async function eposDirectSend(innerXml, o, fetchFn) {
|
|
74
|
-
const
|
|
110
|
+
const zeitlimitMs = o.timeoutMs ?? 10000;
|
|
111
|
+
const url = eposServiceUrl(o.ip, o.devid ?? EPOS_DEVID_VORGABE, zeitlimitMs);
|
|
112
|
+
// `zeitlimitMs` geht zweifach ein -- als `timeout=`-Parameter in der URL
|
|
113
|
+
// (ein Hinweis FUER DEN DRUCKER, wie lange ER intern auf den Kartenfluss/
|
|
114
|
+
// Druckvorgang wartet) UND als AbortController-Frist HIER (die Grenze fuer
|
|
115
|
+
// DIESEN Aufruf). Das ist keine Dopplung, sondern zwei verschiedene Dinge,
|
|
116
|
+
// die zufaellig denselben Wert teilen: ohne die zweite Haelfte begrenzt
|
|
117
|
+
// NICHTS den `fetch()`-Aufruf selbst. Ein Drucker, der die TCP-Verbindung
|
|
118
|
+
// annimmt und nie antwortet (ein reales Fehlerbild bei einem eingebetteten
|
|
119
|
+
// HTTP-Server), liesse den Aufruf dann NIE zurueckkehren und NIE werfen --
|
|
120
|
+
// genau dieses Muster hat im Flutter-Paket einen ganzen Verkauf angehalten:
|
|
121
|
+
// der Beleg stand in der Signaturkette, der Bildschirm zeigte nichts, und
|
|
122
|
+
// ein Neustart mit erneutem Kassieren erzeugte einen zweiten Umsatz.
|
|
123
|
+
const abbruch = new AbortController();
|
|
124
|
+
const wecker = setTimeout(() => abbruch.abort(), zeitlimitMs);
|
|
75
125
|
let antwort;
|
|
126
|
+
let text;
|
|
76
127
|
try {
|
|
77
|
-
|
|
128
|
+
try {
|
|
129
|
+
antwort = await Promise.race([
|
|
130
|
+
fetchFn(url, {
|
|
131
|
+
method: 'POST',
|
|
132
|
+
headers: { 'Content-Type': 'text/xml; charset=utf-8', SOAPAction: '""' },
|
|
133
|
+
body: eposSoapEnvelope(innerXml),
|
|
134
|
+
signal: abbruch.signal,
|
|
135
|
+
}),
|
|
136
|
+
alsAbbruchAbgelehnt(abbruch.signal),
|
|
137
|
+
]);
|
|
138
|
+
// Die Frist deckt auch das Auslesen des Rumpfes, nicht nur den
|
|
139
|
+
// Antwortkopf -- ein Drucker, der den Kopf schickt und den Rumpf offen
|
|
140
|
+
// laesst, haelt den Aufruf sonst trotzdem unbegrenzt fest (dasselbe
|
|
141
|
+
// Muster wie `client/transport.ts`).
|
|
142
|
+
text = await Promise.race([antwort.text(), alsAbbruchAbgelehnt(abbruch.signal)]);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// `abbruch.signal.aborted` ist hier zuverlaessig: der EINZIGE Ausloeser
|
|
146
|
+
// fuer den Abbruch in dieser Funktion ist der `wecker` oben -- jeder
|
|
147
|
+
// andere Fehlschlag (Netz weg, Zertifikat abgelehnt, DNS) laesst das
|
|
148
|
+
// Signal unangetastet.
|
|
149
|
+
throw new EposConnectionError(o.ip, abbruch.signal.aborted);
|
|
150
|
+
}
|
|
78
151
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
'Zugriff aufs lokale Netz erlauben, ePOS-Print am Drucker auf Enable.');
|
|
152
|
+
finally {
|
|
153
|
+
clearTimeout(wecker);
|
|
82
154
|
}
|
|
83
155
|
if (!antwort.ok)
|
|
84
156
|
throw new Error(`Drucker antwortet mit HTTP ${antwort.status}.`);
|
|
85
|
-
return eposParseResponse(
|
|
157
|
+
return eposParseResponse(text);
|
|
86
158
|
}
|
|
87
159
|
/** Beleg direkt drucken; wirft bei Netz-/Zertifikatsproblemen, sonst die Drucker-Antwort. */
|
|
88
160
|
function eposDirectPrint(layout, o, fetchFn = fetch) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { type LayoutAlign, type LayoutColumn, type LayoutTextLine, type LayoutColumnsLine, type LayoutRuleLine, type LayoutSpaceLine, type LayoutQrLine, type LayoutLine, type ReceiptLayout, type BuildReceiptLayoutOptions, buildReceiptLayout, receiptSignatureFailed, receiptSignatureIsTest, receiptIsZero, receiptAmountsAreZero, receiptIsSmallBusinessConsistent, receiptZdaText, type Pruefangaben, AKTUELLES_REGELWERK, type LayoutBannerLine, type LayoutRegelwerk, SMALL_BUSINESS_NOTICE, formatCents, } from './layout.js';
|
|
2
2
|
export { type EscPosLayoutOptions, escPosLayoutBytes } from './layout-escpos.js';
|
|
3
3
|
export { type GridLine, type GridLineKind, type ReceiptGrid, type RenderReceiptGridOptions, renderReceiptGrid, gridSpaltenBreiten, gridAlsText, ZEICHEN_JE_PAPIER, } from './grid.js';
|
|
4
|
-
export { type EposPrintXmlOptions, type EposDirectOptions, type EposResponse, eposPrintXml, eposXmlEscape, eposServiceUrl, eposSoapEnvelope, eposParseResponse, eposDirectPrint, eposDirectStatus } from './epos.js';
|
|
4
|
+
export { type EposPrintXmlOptions, type EposDirectOptions, type EposResponse, EposConnectionError, eposPrintXml, eposXmlEscape, eposServiceUrl, eposSoapEnvelope, eposParseResponse, eposDirectPrint, eposDirectStatus } from './epos.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.eposDirectStatus = exports.eposDirectPrint = exports.eposParseResponse = exports.eposSoapEnvelope = exports.eposServiceUrl = exports.eposXmlEscape = exports.eposPrintXml = exports.ZEICHEN_JE_PAPIER = exports.gridAlsText = exports.gridSpaltenBreiten = exports.renderReceiptGrid = exports.escPosLayoutBytes = exports.formatCents = exports.SMALL_BUSINESS_NOTICE = exports.AKTUELLES_REGELWERK = exports.receiptZdaText = exports.receiptIsSmallBusinessConsistent = exports.receiptAmountsAreZero = exports.receiptIsZero = exports.receiptSignatureIsTest = exports.receiptSignatureFailed = exports.buildReceiptLayout = void 0;
|
|
3
|
+
exports.eposDirectStatus = exports.eposDirectPrint = exports.eposParseResponse = exports.eposSoapEnvelope = exports.eposServiceUrl = exports.eposXmlEscape = exports.eposPrintXml = exports.EposConnectionError = exports.ZEICHEN_JE_PAPIER = exports.gridAlsText = exports.gridSpaltenBreiten = exports.renderReceiptGrid = exports.escPosLayoutBytes = exports.formatCents = exports.SMALL_BUSINESS_NOTICE = exports.AKTUELLES_REGELWERK = exports.receiptZdaText = exports.receiptIsSmallBusinessConsistent = exports.receiptAmountsAreZero = exports.receiptIsZero = exports.receiptSignatureIsTest = exports.receiptSignatureFailed = exports.buildReceiptLayout = void 0;
|
|
4
4
|
var layout_js_1 = require("./layout.js");
|
|
5
5
|
Object.defineProperty(exports, "buildReceiptLayout", { enumerable: true, get: function () { return layout_js_1.buildReceiptLayout; } });
|
|
6
6
|
Object.defineProperty(exports, "receiptSignatureFailed", { enumerable: true, get: function () { return layout_js_1.receiptSignatureFailed; } });
|
|
@@ -20,6 +20,7 @@ Object.defineProperty(exports, "gridSpaltenBreiten", { enumerable: true, get: fu
|
|
|
20
20
|
Object.defineProperty(exports, "gridAlsText", { enumerable: true, get: function () { return grid_js_1.gridAlsText; } });
|
|
21
21
|
Object.defineProperty(exports, "ZEICHEN_JE_PAPIER", { enumerable: true, get: function () { return grid_js_1.ZEICHEN_JE_PAPIER; } });
|
|
22
22
|
var epos_js_1 = require("./epos.js");
|
|
23
|
+
Object.defineProperty(exports, "EposConnectionError", { enumerable: true, get: function () { return epos_js_1.EposConnectionError; } });
|
|
23
24
|
Object.defineProperty(exports, "eposPrintXml", { enumerable: true, get: function () { return epos_js_1.eposPrintXml; } });
|
|
24
25
|
Object.defineProperty(exports, "eposXmlEscape", { enumerable: true, get: function () { return epos_js_1.eposXmlEscape; } });
|
|
25
26
|
Object.defineProperty(exports, "eposServiceUrl", { enumerable: true, get: function () { return epos_js_1.eposServiceUrl; } });
|
|
@@ -48,6 +48,21 @@ function belegZeit(timeStamp) {
|
|
|
48
48
|
const zwei = (n) => String(n).padStart(2, '0');
|
|
49
49
|
return `${zwei(t.day)}.${zwei(t.month)}.${t.year} ${zwei(t.hour)}:${zwei(t.minute)}:${zwei(t.second)}`;
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Datum des stornierten Originals fuer den Kopfblock: „11.08.2026, 09:02 Uhr".
|
|
53
|
+
* Ein unlesbarer Zeitstempel am BEZUG ist kein Grund, den Storno-Bon zu
|
|
54
|
+
* verweigern (der Beleg selbst ist gueltig) — dann bleibt die Zeile weg.
|
|
55
|
+
*/
|
|
56
|
+
function originalDatum(timeStamp) {
|
|
57
|
+
try {
|
|
58
|
+
const t = (0, vienna_time_js_1.toViennaWallClock)((0, vienna_time_js_1.parseServerTimeStamp)(timeStamp));
|
|
59
|
+
const zwei = (n) => String(n).padStart(2, '0');
|
|
60
|
+
return `${zwei(t.day)}.${zwei(t.month)}.${t.year}, ${zwei(t.hour)}:${zwei(t.minute)} Uhr`;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
51
66
|
/**
|
|
52
67
|
* Zahlungsart als Anzeigetext. Drei Faelle, und alle drei kommen vor:
|
|
53
68
|
* bekannter Eintrag (Beschriftung), unbekannter Schluessel (roh — besser als
|
|
@@ -415,6 +430,10 @@ function belegartBlock(receipt) {
|
|
|
415
430
|
if (t === 'cancellation') {
|
|
416
431
|
aus.push(bannerZeile('STORNOBELEG'));
|
|
417
432
|
aus.push(textZeile(receipt.cancellationOf ? `Stornobuchung zu Beleg ${receipt.cancellationOf.receiptId}` : 'Stornobuchung', 'center'));
|
|
433
|
+
// Datum des Originals, wenn der Bezug es traegt (Backend seit 2026-09-04).
|
|
434
|
+
const datum = receipt.cancellationOf?.timeStamp ? originalDatum(receipt.cancellationOf.timeStamp) : null;
|
|
435
|
+
if (datum)
|
|
436
|
+
aus.push(textZeile(`vom ${datum}`, 'center'));
|
|
418
437
|
const grund = stornoGrundText(typeof receipt.cancellationReason === 'string' ? receipt.cancellationReason : undefined);
|
|
419
438
|
if (grund)
|
|
420
439
|
aus.push(textZeile(`Grund: ${grund}`, 'center'));
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
* daraus entstehende ID-Token und `sitzung.sessionId` ergeben zusammen
|
|
48
48
|
* `registerUserAuth` — ab da laeuft alles Weitere ueber den ueblichen Weg.
|
|
49
49
|
*/
|
|
50
|
-
export { type RegisterDeviceConnection, type RegisterDeviceCredentials, type PairRegisterDeviceOptions, type PairedRegisterDevice, type RegisterUserKind, type RegisterUserSummary, type RegisterUserPerms, REGISTER_PERMS, type RegisterScope, type RegisterUser, type RegisterUserSession, type ListRegisterUsersForDeviceOptions, type RegisterUserLoginOptions, type RegisterPinLoginOptions, type RegisterPinPolicy, type RegisterLoginMode, type RegisterDeviceUsers, type RegisterClientInfo, type RegisterGeo, type RegisterGeraeteAngaben, pairRegisterDevice, listRegisterUsersForDevice, unpairRegisterDevice, registerUserLogin, registerPinLogin, } from './pairing.js';
|
|
50
|
+
export { type RegisterDeviceConnection, type RegisterDeviceCredentials, type PairRegisterDeviceOptions, type PairedRegisterDevice, type RegisterUserKind, type RegisterUserSummary, type RegisterUserPerms, REGISTER_PERMS, type RegisterScope, type RegisterUser, type RegisterUserSession, type ListRegisterUsersForDeviceOptions, type RegisterUserLoginOptions, type RegisterPinLoginOptions, type RegisterPinPolicy, type RegisterLoginMode, type RegisterDeviceUsers, type RegisterClientInfo, type RegisterGeo, type RegisterGeraeteAngaben, type RegisterSession, type RegisterSessionsStand, type ListRegisterSessionsForDeviceOptions, pairRegisterDevice, listRegisterUsersForDevice, listRegisterSessionsForDevice, unpairRegisterDevice, registerUserLogin, registerPinLogin, } from './pairing.js';
|
|
51
51
|
export { renewRegisterSession, endRegisterSession } from './session.js';
|
|
@@ -49,11 +49,12 @@
|
|
|
49
49
|
* `registerUserAuth` — ab da laeuft alles Weitere ueber den ueblichen Weg.
|
|
50
50
|
*/
|
|
51
51
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52
|
-
exports.endRegisterSession = exports.renewRegisterSession = exports.registerPinLogin = exports.registerUserLogin = exports.unpairRegisterDevice = exports.listRegisterUsersForDevice = exports.pairRegisterDevice = exports.REGISTER_PERMS = void 0;
|
|
52
|
+
exports.endRegisterSession = exports.renewRegisterSession = exports.registerPinLogin = exports.registerUserLogin = exports.unpairRegisterDevice = exports.listRegisterSessionsForDevice = exports.listRegisterUsersForDevice = exports.pairRegisterDevice = exports.REGISTER_PERMS = void 0;
|
|
53
53
|
var pairing_js_1 = require("./pairing.js");
|
|
54
54
|
Object.defineProperty(exports, "REGISTER_PERMS", { enumerable: true, get: function () { return pairing_js_1.REGISTER_PERMS; } });
|
|
55
55
|
Object.defineProperty(exports, "pairRegisterDevice", { enumerable: true, get: function () { return pairing_js_1.pairRegisterDevice; } });
|
|
56
56
|
Object.defineProperty(exports, "listRegisterUsersForDevice", { enumerable: true, get: function () { return pairing_js_1.listRegisterUsersForDevice; } });
|
|
57
|
+
Object.defineProperty(exports, "listRegisterSessionsForDevice", { enumerable: true, get: function () { return pairing_js_1.listRegisterSessionsForDevice; } });
|
|
57
58
|
Object.defineProperty(exports, "unpairRegisterDevice", { enumerable: true, get: function () { return pairing_js_1.unpairRegisterDevice; } });
|
|
58
59
|
Object.defineProperty(exports, "registerUserLogin", { enumerable: true, get: function () { return pairing_js_1.registerUserLogin; } });
|
|
59
60
|
Object.defineProperty(exports, "registerPinLogin", { enumerable: true, get: function () { return pairing_js_1.registerPinLogin; } });
|