@kreiseck/kasseneck-api 0.6.7
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/LICENSE +201 -0
- package/NOTICE +2 -0
- package/README.md +206 -0
- package/dist/cjs/client/api.d.ts +75 -0
- package/dist/cjs/client/api.js +40 -0
- package/dist/cjs/client/auth.d.ts +52 -0
- package/dist/cjs/client/auth.js +72 -0
- package/dist/cjs/client/cashregisters.d.ts +21 -0
- package/dist/cjs/client/cashregisters.js +36 -0
- package/dist/cjs/client/errors.d.ts +159 -0
- package/dist/cjs/client/errors.js +226 -0
- package/dist/cjs/client/index.d.ts +8 -0
- package/dist/cjs/client/index.js +44 -0
- package/dist/cjs/client/receipts.d.ts +245 -0
- package/dist/cjs/client/receipts.js +452 -0
- package/dist/cjs/client/reports.d.ts +43 -0
- package/dist/cjs/client/reports.js +73 -0
- package/dist/cjs/client/status.d.ts +43 -0
- package/dist/cjs/client/status.js +47 -0
- package/dist/cjs/client/transport.d.ts +117 -0
- package/dist/cjs/client/transport.js +312 -0
- package/dist/cjs/enums/credit-card-provider.d.ts +22 -0
- package/dist/cjs/enums/credit-card-provider.js +23 -0
- package/dist/cjs/enums/define-enum.d.ts +15 -0
- package/dist/cjs/enums/define-enum.js +16 -0
- package/dist/cjs/enums/index.d.ts +7 -0
- package/dist/cjs/enums/index.js +17 -0
- package/dist/cjs/enums/keck-payment-method.d.ts +57 -0
- package/dist/cjs/enums/keck-payment-method.js +23 -0
- package/dist/cjs/enums/receipt-type.d.ts +41 -0
- package/dist/cjs/enums/receipt-type.js +18 -0
- package/dist/cjs/enums/stripe-link-mode.d.ts +17 -0
- package/dist/cjs/enums/stripe-link-mode.js +18 -0
- package/dist/cjs/enums/vat-rate.d.ts +40 -0
- package/dist/cjs/enums/vat-rate.js +19 -0
- package/dist/cjs/enums/voucher-action.d.ts +10 -0
- package/dist/cjs/enums/voucher-action.js +11 -0
- package/dist/cjs/enums/voucher-type.d.ts +9 -0
- package/dist/cjs/enums/voucher-type.js +10 -0
- package/dist/cjs/index.d.ts +5 -0
- package/dist/cjs/index.js +97 -0
- package/dist/cjs/kasse/artikel.d.ts +83 -0
- package/dist/cjs/kasse/artikel.js +79 -0
- package/dist/cjs/kasse/client.d.ts +10 -0
- package/dist/cjs/kasse/client.js +38 -0
- package/dist/cjs/kasse/drucker.d.ts +54 -0
- package/dist/cjs/kasse/drucker.js +41 -0
- package/dist/cjs/kasse/index.d.ts +11 -0
- package/dist/cjs/kasse/index.js +38 -0
- package/dist/cjs/kasse/settings.d.ts +115 -0
- package/dist/cjs/kasse/settings.js +62 -0
- package/dist/cjs/models/cancellation.d.ts +51 -0
- package/dist/cjs/models/cancellation.js +45 -0
- package/dist/cjs/models/cashregister.d.ts +77 -0
- package/dist/cjs/models/cashregister.js +53 -0
- package/dist/cjs/models/enum-payload.d.ts +26 -0
- package/dist/cjs/models/enum-payload.js +50 -0
- package/dist/cjs/models/hobex-receipt.d.ts +63 -0
- package/dist/cjs/models/hobex-receipt.js +86 -0
- package/dist/cjs/models/index.d.ts +10 -0
- package/dist/cjs/models/index.js +46 -0
- package/dist/cjs/models/receipt-company.d.ts +71 -0
- package/dist/cjs/models/receipt-company.js +52 -0
- package/dist/cjs/models/receipt-item.d.ts +100 -0
- package/dist/cjs/models/receipt-item.js +108 -0
- package/dist/cjs/models/receipt-summary.d.ts +92 -0
- package/dist/cjs/models/receipt-summary.js +54 -0
- package/dist/cjs/models/receipt.d.ts +108 -0
- package/dist/cjs/models/receipt.js +119 -0
- package/dist/cjs/models/report-month.d.ts +32 -0
- package/dist/cjs/models/report-month.js +65 -0
- package/dist/cjs/models/stripe-url-session.d.ts +18 -0
- package/dist/cjs/models/stripe-url-session.js +20 -0
- package/dist/cjs/models/voucher.d.ts +41 -0
- package/dist/cjs/models/voucher.js +56 -0
- package/dist/cjs/money.d.ts +23 -0
- package/dist/cjs/money.js +35 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/payments/hobex.d.ts +87 -0
- package/dist/cjs/payments/hobex.js +167 -0
- package/dist/cjs/payments/index.d.ts +33 -0
- package/dist/cjs/payments/index.js +42 -0
- package/dist/cjs/payments/stripe.d.ts +61 -0
- package/dist/cjs/payments/stripe.js +157 -0
- package/dist/cjs/printing/escpos.d.ts +219 -0
- package/dist/cjs/printing/escpos.js +636 -0
- package/dist/cjs/printing/index.d.ts +3 -0
- package/dist/cjs/printing/index.js +33 -0
- package/dist/cjs/printing/printable.d.ts +27 -0
- package/dist/cjs/printing/printable.js +90 -0
- package/dist/cjs/printing/webusb.d.ts +89 -0
- package/dist/cjs/printing/webusb.js +110 -0
- package/dist/cjs/react/index.d.ts +46 -0
- package/dist/cjs/react/index.js +51 -0
- package/dist/cjs/receipt/discount.d.ts +12 -0
- package/dist/cjs/receipt/discount.js +54 -0
- package/dist/cjs/receipt/epos.d.ts +53 -0
- package/dist/cjs/receipt/epos.js +95 -0
- package/dist/cjs/receipt/grid.d.ts +47 -0
- package/dist/cjs/receipt/grid.js +122 -0
- package/dist/cjs/receipt/index.d.ts +4 -0
- package/dist/cjs/receipt/index.js +29 -0
- package/dist/cjs/receipt/layout-escpos.d.ts +35 -0
- package/dist/cjs/receipt/layout-escpos.js +67 -0
- package/dist/cjs/receipt/layout.d.ts +180 -0
- package/dist/cjs/receipt/layout.js +594 -0
- package/dist/cjs/register/index.d.ts +51 -0
- package/dist/cjs/register/index.js +61 -0
- package/dist/cjs/register/pairing.d.ts +248 -0
- package/dist/cjs/register/pairing.js +279 -0
- package/dist/cjs/register/session.d.ts +37 -0
- package/dist/cjs/register/session.js +52 -0
- package/dist/cjs/vienna-time.d.ts +23 -0
- package/dist/cjs/vienna-time.js +114 -0
- package/dist/esm/client/api.d.ts +75 -0
- package/dist/esm/client/api.js +37 -0
- package/dist/esm/client/auth.d.ts +52 -0
- package/dist/esm/client/auth.js +68 -0
- package/dist/esm/client/cashregisters.d.ts +21 -0
- package/dist/esm/client/cashregisters.js +33 -0
- package/dist/esm/client/errors.d.ts +159 -0
- package/dist/esm/client/errors.js +212 -0
- package/dist/esm/client/index.d.ts +8 -0
- package/dist/esm/client/index.js +8 -0
- package/dist/esm/client/receipts.d.ts +245 -0
- package/dist/esm/client/receipts.js +438 -0
- package/dist/esm/client/reports.d.ts +43 -0
- package/dist/esm/client/reports.js +69 -0
- package/dist/esm/client/status.d.ts +43 -0
- package/dist/esm/client/status.js +43 -0
- package/dist/esm/client/transport.d.ts +117 -0
- package/dist/esm/client/transport.js +307 -0
- package/dist/esm/enums/credit-card-provider.d.ts +22 -0
- package/dist/esm/enums/credit-card-provider.js +20 -0
- package/dist/esm/enums/define-enum.d.ts +15 -0
- package/dist/esm/enums/define-enum.js +13 -0
- package/dist/esm/enums/index.d.ts +7 -0
- package/dist/esm/enums/index.js +7 -0
- package/dist/esm/enums/keck-payment-method.d.ts +57 -0
- package/dist/esm/enums/keck-payment-method.js +20 -0
- package/dist/esm/enums/receipt-type.d.ts +41 -0
- package/dist/esm/enums/receipt-type.js +15 -0
- package/dist/esm/enums/stripe-link-mode.d.ts +17 -0
- package/dist/esm/enums/stripe-link-mode.js +15 -0
- package/dist/esm/enums/vat-rate.d.ts +40 -0
- package/dist/esm/enums/vat-rate.js +16 -0
- package/dist/esm/enums/voucher-action.d.ts +10 -0
- package/dist/esm/enums/voucher-action.js +8 -0
- package/dist/esm/enums/voucher-type.d.ts +9 -0
- package/dist/esm/enums/voucher-type.js +7 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/kasse/artikel.d.ts +83 -0
- package/dist/esm/kasse/artikel.js +70 -0
- package/dist/esm/kasse/client.d.ts +10 -0
- package/dist/esm/kasse/client.js +33 -0
- package/dist/esm/kasse/drucker.d.ts +54 -0
- package/dist/esm/kasse/drucker.js +36 -0
- package/dist/esm/kasse/index.d.ts +11 -0
- package/dist/esm/kasse/index.js +13 -0
- package/dist/esm/kasse/settings.d.ts +115 -0
- package/dist/esm/kasse/settings.js +58 -0
- package/dist/esm/models/cancellation.d.ts +51 -0
- package/dist/esm/models/cancellation.js +40 -0
- package/dist/esm/models/cashregister.d.ts +77 -0
- package/dist/esm/models/cashregister.js +50 -0
- package/dist/esm/models/enum-payload.d.ts +26 -0
- package/dist/esm/models/enum-payload.js +44 -0
- package/dist/esm/models/hobex-receipt.d.ts +63 -0
- package/dist/esm/models/hobex-receipt.js +80 -0
- package/dist/esm/models/index.d.ts +10 -0
- package/dist/esm/models/index.js +10 -0
- package/dist/esm/models/receipt-company.d.ts +71 -0
- package/dist/esm/models/receipt-company.js +48 -0
- package/dist/esm/models/receipt-item.d.ts +100 -0
- package/dist/esm/models/receipt-item.js +101 -0
- package/dist/esm/models/receipt-summary.d.ts +92 -0
- package/dist/esm/models/receipt-summary.js +49 -0
- package/dist/esm/models/receipt.d.ts +108 -0
- package/dist/esm/models/receipt.js +113 -0
- package/dist/esm/models/report-month.d.ts +32 -0
- package/dist/esm/models/report-month.js +58 -0
- package/dist/esm/models/stripe-url-session.d.ts +18 -0
- package/dist/esm/models/stripe-url-session.js +16 -0
- package/dist/esm/models/voucher.d.ts +41 -0
- package/dist/esm/models/voucher.js +51 -0
- package/dist/esm/money.d.ts +23 -0
- package/dist/esm/money.js +31 -0
- package/dist/esm/payments/hobex.d.ts +87 -0
- package/dist/esm/payments/hobex.js +162 -0
- package/dist/esm/payments/index.d.ts +33 -0
- package/dist/esm/payments/index.js +33 -0
- package/dist/esm/payments/stripe.d.ts +61 -0
- package/dist/esm/payments/stripe.js +153 -0
- package/dist/esm/printing/escpos.d.ts +219 -0
- package/dist/esm/printing/escpos.js +616 -0
- package/dist/esm/printing/index.d.ts +3 -0
- package/dist/esm/printing/index.js +3 -0
- package/dist/esm/printing/printable.d.ts +27 -0
- package/dist/esm/printing/printable.js +87 -0
- package/dist/esm/printing/webusb.d.ts +89 -0
- package/dist/esm/printing/webusb.js +101 -0
- package/dist/esm/react/index.d.ts +46 -0
- package/dist/esm/react/index.js +47 -0
- package/dist/esm/receipt/discount.d.ts +12 -0
- package/dist/esm/receipt/discount.js +51 -0
- package/dist/esm/receipt/epos.d.ts +53 -0
- package/dist/esm/receipt/epos.js +86 -0
- package/dist/esm/receipt/grid.d.ts +47 -0
- package/dist/esm/receipt/grid.js +116 -0
- package/dist/esm/receipt/index.d.ts +4 -0
- package/dist/esm/receipt/index.js +4 -0
- package/dist/esm/receipt/layout-escpos.d.ts +35 -0
- package/dist/esm/receipt/layout-escpos.js +64 -0
- package/dist/esm/receipt/layout.d.ts +180 -0
- package/dist/esm/receipt/layout.js +583 -0
- package/dist/esm/register/index.d.ts +51 -0
- package/dist/esm/register/index.js +51 -0
- package/dist/esm/register/pairing.d.ts +248 -0
- package/dist/esm/register/pairing.js +270 -0
- package/dist/esm/register/session.d.ts +37 -0
- package/dist/esm/register/session.js +48 -0
- package/dist/esm/vienna-time.d.ts +23 -0
- package/dist/esm/vienna-time.js +110 -0
- package/fixtures/belege/langer-artikelname.json +43 -0
- package/fixtures/belege/null-ausfall.json +41 -0
- package/fixtures/belege/null-jahr.json +41 -0
- package/fixtures/belege/null-monat.json +41 -0
- package/fixtures/belege/null-pruef.json +41 -0
- package/fixtures/belege/null-schluss.json +41 -0
- package/fixtures/belege/null-start.json +40 -0
- package/fixtures/belege/rabattzeilen.json +61 -0
- package/fixtures/belege/signaturausfall-verkauf.json +49 -0
- package/fixtures/belege/storno-teil.json +48 -0
- package/fixtures/belege/storno-voll.json +54 -0
- package/fixtures/belege/testkasse-verkauf.json +50 -0
- package/fixtures/belege/testsignatur-verkauf.json +50 -0
- package/fixtures/belege/training.json +49 -0
- package/fixtures/belege/verkauf-bar.json +49 -0
- package/fixtures/belege/verkauf-karte.json +49 -0
- package/fixtures/belege/verkauf-kleinunternehmer.json +42 -0
- package/fixtures/erwartet/langer-artikelname.grid32.txt +25 -0
- package/fixtures/erwartet/langer-artikelname.grid48.txt +24 -0
- package/fixtures/erwartet/langer-artikelname.lines.json +216 -0
- package/fixtures/erwartet/null-ausfall.grid32.txt +28 -0
- package/fixtures/erwartet/null-ausfall.grid48.txt +25 -0
- package/fixtures/erwartet/null-ausfall.lines.json +220 -0
- package/fixtures/erwartet/null-jahr.grid32.txt +29 -0
- package/fixtures/erwartet/null-jahr.grid48.txt +25 -0
- package/fixtures/erwartet/null-jahr.lines.json +220 -0
- package/fixtures/erwartet/null-monat.grid32.txt +28 -0
- package/fixtures/erwartet/null-monat.grid48.txt +25 -0
- package/fixtures/erwartet/null-monat.lines.json +220 -0
- package/fixtures/erwartet/null-pruef.grid32.txt +28 -0
- package/fixtures/erwartet/null-pruef.grid48.txt +25 -0
- package/fixtures/erwartet/null-pruef.lines.json +220 -0
- package/fixtures/erwartet/null-schluss.grid32.txt +28 -0
- package/fixtures/erwartet/null-schluss.grid48.txt +25 -0
- package/fixtures/erwartet/null-schluss.lines.json +220 -0
- package/fixtures/erwartet/null-start.grid32.txt +28 -0
- package/fixtures/erwartet/null-start.grid48.txt +25 -0
- package/fixtures/erwartet/null-start.lines.json +220 -0
- package/fixtures/erwartet/rabattzeilen.grid32.txt +27 -0
- package/fixtures/erwartet/rabattzeilen.grid48.txt +26 -0
- package/fixtures/erwartet/rabattzeilen.lines.json +286 -0
- package/fixtures/erwartet/signaturausfall-verkauf.grid32.txt +28 -0
- package/fixtures/erwartet/signaturausfall-verkauf.grid48.txt +26 -0
- package/fixtures/erwartet/signaturausfall-verkauf.lines.json +266 -0
- package/fixtures/erwartet/storno-teil.grid32.txt +27 -0
- package/fixtures/erwartet/storno-teil.grid48.txt +26 -0
- package/fixtures/erwartet/storno-teil.lines.json +237 -0
- package/fixtures/erwartet/storno-voll.grid32.txt +29 -0
- package/fixtures/erwartet/storno-voll.grid48.txt +28 -0
- package/fixtures/erwartet/storno-voll.lines.json +277 -0
- package/fixtures/erwartet/testkasse-verkauf.grid32.txt +28 -0
- package/fixtures/erwartet/testkasse-verkauf.grid48.txt +27 -0
- package/fixtures/erwartet/testkasse-verkauf.lines.json +270 -0
- package/fixtures/erwartet/testsignatur-verkauf.grid32.txt +30 -0
- package/fixtures/erwartet/testsignatur-verkauf.grid48.txt +27 -0
- package/fixtures/erwartet/testsignatur-verkauf.lines.json +270 -0
- package/fixtures/erwartet/training.grid32.txt +33 -0
- package/fixtures/erwartet/training.grid48.txt +30 -0
- package/fixtures/erwartet/training.lines.json +277 -0
- package/fixtures/erwartet/verkauf-bar.grid32.txt +25 -0
- package/fixtures/erwartet/verkauf-bar.grid48.txt +24 -0
- package/fixtures/erwartet/verkauf-bar.lines.json +256 -0
- package/fixtures/erwartet/verkauf-karte.grid32.txt +25 -0
- package/fixtures/erwartet/verkauf-karte.grid48.txt +24 -0
- package/fixtures/erwartet/verkauf-karte.lines.json +256 -0
- package/fixtures/erwartet/verkauf-kleinunternehmer.grid32.txt +26 -0
- package/fixtures/erwartet/verkauf-kleinunternehmer.grid48.txt +25 -0
- package/fixtures/erwartet/verkauf-kleinunternehmer.lines.json +226 -0
- package/fixtures/manifest.json +107 -0
- package/package.json +135 -0
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createReceipt = createReceipt;
|
|
4
|
+
exports.sellReceipt = sellReceipt;
|
|
5
|
+
exports.sellReceiptWithCompany = sellReceiptWithCompany;
|
|
6
|
+
exports.cancelReceipt = cancelReceipt;
|
|
7
|
+
exports.createCancelReceipt = createCancelReceipt;
|
|
8
|
+
exports.zeroReceipt = zeroReceipt;
|
|
9
|
+
exports.listMyReceipts = listMyReceipts;
|
|
10
|
+
exports.getReceipt = getReceipt;
|
|
11
|
+
exports.getReceiptWithCompany = getReceiptWithCompany;
|
|
12
|
+
exports.generateFullReceiptId = generateFullReceiptId;
|
|
13
|
+
exports.getFirstReceiptDate = getFirstReceiptDate;
|
|
14
|
+
exports.checkVoucherCombinationError = checkVoucherCombinationError;
|
|
15
|
+
const index_js_1 = require("../enums/index.js");
|
|
16
|
+
const index_js_2 = require("../models/index.js");
|
|
17
|
+
const vienna_time_js_1 = require("../vienna-time.js");
|
|
18
|
+
const money_js_1 = require("../money.js");
|
|
19
|
+
const errors_js_1 = require("./errors.js");
|
|
20
|
+
/**
|
|
21
|
+
* Gemeinsame Umsetzung aller Belegarten (Zwilling von `_createReceipt`).
|
|
22
|
+
* Bewusst **nicht** Teil der Paketoberflaeche: der Belegtyp gehoert nicht in
|
|
23
|
+
* die Hand des Aufrufers, sondern zu einem der benannten Aufrufe darunter.
|
|
24
|
+
*/
|
|
25
|
+
async function createReceipt(rufen, options) {
|
|
26
|
+
return belegAusHuelle(await rufen('createReceipt', createReceiptParams(options)), 'createReceipt');
|
|
27
|
+
}
|
|
28
|
+
/** Wie [createReceipt], liest aus derselben Antwort zusaetzlich die Firmendaten. */
|
|
29
|
+
async function createReceiptWithCompany(rufen, options) {
|
|
30
|
+
return belegMitFirmaAusHuelle(await rufen('createReceipt', createReceiptParams(options)), 'createReceipt');
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Baut die Nutzlast von `createReceipt` und prueft die Eingabe. Wirft, bevor
|
|
34
|
+
* irgendetwas rausgeht — ein Beleg ist nicht folgenlos wiederholbar.
|
|
35
|
+
*/
|
|
36
|
+
function createReceiptParams(options) {
|
|
37
|
+
const typ = belegtyp(options.receiptType);
|
|
38
|
+
const { items, vouchers } = options;
|
|
39
|
+
if (typ.needsItems) {
|
|
40
|
+
// Ein reiner Gutscheinverkauf ist ein Umsatz ohne Positionen — deshalb
|
|
41
|
+
// zaehlt er hier wie eine Position (wie im Flutter-Vorbild).
|
|
42
|
+
const hatVerkaufsgutschein = vouchers?.some((v) => v.action === index_js_1.VoucherAction.sell) ?? false;
|
|
43
|
+
if ((items == null || items.length === 0) && !hatVerkaufsgutschein) {
|
|
44
|
+
throw eingabefehler(`Positionen sind Pflicht bei receiptType "${typ.value}" und duerfen nicht leer sein.`);
|
|
45
|
+
}
|
|
46
|
+
if (items?.some((item) => !(0, index_js_2.receiptItemIsValid)(item)) ?? false) {
|
|
47
|
+
throw eingabefehler('Ungueltige Position uebergeben.');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const params = { receiptType: typ.value };
|
|
51
|
+
if (vouchers != null && vouchers.length > 0) {
|
|
52
|
+
if (!typ.allowsVouchers) {
|
|
53
|
+
throw eingabefehler(`Gutscheine sind nicht erlaubt bei receiptType "${typ.value}".`);
|
|
54
|
+
}
|
|
55
|
+
if (vouchers.some((voucher) => !(0, index_js_2.voucherIsValid)(voucher))) {
|
|
56
|
+
throw eingabefehler('Ungueltiger Gutschein uebergeben.');
|
|
57
|
+
}
|
|
58
|
+
const kombinationsfehler = checkVoucherCombinationError(vouchers, items ?? []);
|
|
59
|
+
if (kombinationsfehler != null) {
|
|
60
|
+
throw eingabefehler(kombinationsfehler);
|
|
61
|
+
}
|
|
62
|
+
params['vouchers'] = alsNutzlast(vouchers, index_js_2.toVoucherPayload);
|
|
63
|
+
}
|
|
64
|
+
if (items != null && items.length > 0) {
|
|
65
|
+
params['items'] = alsNutzlast(items, index_js_2.toReceiptItemPayload);
|
|
66
|
+
}
|
|
67
|
+
// Vom Aufrufer kommt sie geprueft, vom Server roh — siehe die beiden Felder
|
|
68
|
+
// in [CreateReceiptOptions]. Die Typpruefung allein reicht dafuer nicht: ein
|
|
69
|
+
// Verbraucher ohne Typen faellt durch dieses Netz, und ein Tippfehler in der
|
|
70
|
+
// Zahlungsart faellt sonst erst am Server auf.
|
|
71
|
+
const zahlungsart = options.paymentMethod != null ? gepruefteZahlungsart(options.paymentMethod) : options.paymentMethodFromServer;
|
|
72
|
+
if (zahlungsart != null) {
|
|
73
|
+
params['paymentMethod'] = zahlungsart;
|
|
74
|
+
const anbieter = options.creditCardProvider ?? index_js_1.CreditCardProvider.custom;
|
|
75
|
+
if (zahlungsart === index_js_1.KeckPaymentMethod.creditCard.value) {
|
|
76
|
+
if (options.cardPaymentId != null) {
|
|
77
|
+
params['cardPaymentId'] = options.cardPaymentId;
|
|
78
|
+
// Der Kartenanbieter kommt dagegen vom Aufrufer, nicht vom Server —
|
|
79
|
+
// hier bleibt der Schreibpfad streng.
|
|
80
|
+
params['creditCardProvider'] = kartenanbieter(anbieter);
|
|
81
|
+
// Bewusst auch als `null`, wenn der Anbieter keine Rohdaten liefert:
|
|
82
|
+
// das Feld gehoert zur Kartenzahlung und das Backend nimmt null an.
|
|
83
|
+
params['cardPaymentData'] = options.cardPaymentData ?? null;
|
|
84
|
+
}
|
|
85
|
+
else if (anbieter !== index_js_1.CreditCardProvider.custom) {
|
|
86
|
+
throw eingabefehler(`cardPaymentId ist Pflicht bei creditCardProvider "${anbieter}".`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (options.customProjectId != null) {
|
|
91
|
+
params['customProjectId'] = options.customProjectId;
|
|
92
|
+
}
|
|
93
|
+
if (options.customerDetails != null) {
|
|
94
|
+
params['customerDetails'] = options.customerDetails.join('\n');
|
|
95
|
+
}
|
|
96
|
+
if (options.legalMessage != null) {
|
|
97
|
+
params['legalMessage'] = options.legalMessage.join('\n');
|
|
98
|
+
}
|
|
99
|
+
return params;
|
|
100
|
+
}
|
|
101
|
+
/** Normalbeleg (Verkauf) nach RKSV. */
|
|
102
|
+
function sellReceipt(rufen, options) {
|
|
103
|
+
return createReceipt(rufen, { ...options, receiptType: index_js_1.ReceiptType.standard });
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Normalbeleg wie [sellReceipt], liefert zusaetzlich die Firmen-/Druckdaten
|
|
107
|
+
* aus derselben Antwort — alles, was ein Belegdruck braucht, in einem Aufruf.
|
|
108
|
+
*/
|
|
109
|
+
function sellReceiptWithCompany(rufen, options) {
|
|
110
|
+
return createReceiptWithCompany(rufen, { ...options, receiptType: index_js_1.ReceiptType.standard });
|
|
111
|
+
}
|
|
112
|
+
const NOTE_MAX = 200;
|
|
113
|
+
/**
|
|
114
|
+
* Storno-Beleg zu einem bestehenden Beleg — voll oder in Teilen. Prueft die
|
|
115
|
+
* Eingabe, bevor etwas hinausgeht; der Server haelt die Restmengen und die
|
|
116
|
+
* Reichweite des Rechts (eigene/alle) und antwortet mit dem fertigen,
|
|
117
|
+
* signierten Storno-Beleg. Gutscheine des Originals wandern nicht mit.
|
|
118
|
+
*/
|
|
119
|
+
async function cancelReceipt(rufen, options) {
|
|
120
|
+
const cashregisterId = options.receipt?.cashregisterId ?? options.cashregisterId;
|
|
121
|
+
const originalReceiptId = options.receipt?.receiptId ?? options.originalReceiptId;
|
|
122
|
+
if (typeof cashregisterId !== 'string' || cashregisterId.trim() === '') {
|
|
123
|
+
throw new errors_js_1.KasseneckValidationError('cancelReceipt', 'cashregisterId fehlt', 'request');
|
|
124
|
+
}
|
|
125
|
+
if (typeof originalReceiptId !== 'string' || originalReceiptId.trim() === '') {
|
|
126
|
+
throw new errors_js_1.KasseneckValidationError('cancelReceipt', 'originalReceiptId fehlt', 'request');
|
|
127
|
+
}
|
|
128
|
+
if (!(0, index_js_2.isCancellationReason)(options.reason)) {
|
|
129
|
+
throw new errors_js_1.KasseneckValidationError('cancelReceipt', 'Storno-Grund fehlt oder ist unbekannt', 'request');
|
|
130
|
+
}
|
|
131
|
+
if (options.items !== undefined) {
|
|
132
|
+
if (!Array.isArray(options.items) || options.items.length === 0) {
|
|
133
|
+
throw new errors_js_1.KasseneckValidationError('cancelReceipt', 'items muss eine nicht leere Liste sein', 'request');
|
|
134
|
+
}
|
|
135
|
+
for (const pos of options.items) {
|
|
136
|
+
if (!Number.isInteger(pos.index) || pos.index < 0 || !Number.isInteger(pos.quantity) || pos.quantity < 1) {
|
|
137
|
+
throw new errors_js_1.KasseneckValidationError('cancelReceipt', 'Storno-Menge muss eine ganze Zahl >= 1 sein', 'request');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (options.note !== undefined && options.note.length > NOTE_MAX) {
|
|
142
|
+
throw new errors_js_1.KasseneckValidationError('cancelReceipt', `Anmerkung ist zu lang (hoechstens ${NOTE_MAX} Zeichen)`, 'request');
|
|
143
|
+
}
|
|
144
|
+
const params = { cashregisterId, originalReceiptId, reason: options.reason };
|
|
145
|
+
if (options.items !== undefined)
|
|
146
|
+
params.items = options.items.map((p) => ({ index: p.index, quantity: p.quantity }));
|
|
147
|
+
if (options.note !== undefined && options.note !== '')
|
|
148
|
+
params.note = options.note;
|
|
149
|
+
if (options.paymentMethod != null)
|
|
150
|
+
params.paymentMethod = gepruefteZahlungsart(options.paymentMethod);
|
|
151
|
+
const daten = await rufen('cancelReceipt', params);
|
|
152
|
+
const receipt = belegAusHuelle(daten, 'cancelReceipt');
|
|
153
|
+
const huelle = daten;
|
|
154
|
+
const bezug = huelle.cancellationOf;
|
|
155
|
+
if (bezug == null || typeof bezug.receiptId !== 'string') {
|
|
156
|
+
throw antwortfehler('cancelReceipt', 'Antwort enthaelt keinen Bezug (data.cancellationOf fehlt)');
|
|
157
|
+
}
|
|
158
|
+
if (!Array.isArray(huelle.remaining) || !huelle.remaining.every((n) => Number.isInteger(n))) {
|
|
159
|
+
throw antwortfehler('cancelReceipt', 'Antwort enthaelt keine Restmengen (data.remaining fehlt)');
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
receipt,
|
|
163
|
+
cancellationOf: { receiptId: bezug.receiptId, fullReceiptId: typeof bezug.fullReceiptId === 'string' ? bezug.fullReceiptId : null },
|
|
164
|
+
remaining: huelle.remaining,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Stornobeleg aus frei uebergebenen Positionen — fuer den Fall, dass der
|
|
169
|
+
* Originalbeleg nicht als Objekt vorliegt. Die Positionen gehen **unveraendert**
|
|
170
|
+
* hinaus; das Vorzeichen setzt der Aufrufer.
|
|
171
|
+
*/
|
|
172
|
+
function createCancelReceipt(rufen, options) {
|
|
173
|
+
return createReceipt(rufen, { ...options, receiptType: index_js_1.ReceiptType.cancellation });
|
|
174
|
+
}
|
|
175
|
+
/** Nullbeleg (RKSV-Pruefbeleg) — ohne Positionen und ohne Zahlungsart. */
|
|
176
|
+
function zeroReceipt(rufen) {
|
|
177
|
+
return createReceipt(rufen, { receiptType: index_js_1.ReceiptType.zero });
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Belege einer Kasse auflisten — die Grundlage jeder Belegliste in der
|
|
181
|
+
* Browser-Kasse (Nachdruck, Storno, Tagesuebersicht).
|
|
182
|
+
*
|
|
183
|
+
* Die Eintraege sind **Zusammenfassungen**, keine vollstaendigen Belege (siehe
|
|
184
|
+
* [ReceiptSummary]); fuer Nachdruck oder Storno gehoert der Beleg ueber
|
|
185
|
+
* [getReceipt] bzw. [getReceiptWithCompany] einzeln geholt.
|
|
186
|
+
*
|
|
187
|
+
* **Anmeldeweg:** Der Endpunkt laeuft im Backend unter
|
|
188
|
+
* `checkRequest(req, 'customer', …, {allowRegisterUser: true})`, der Bearer
|
|
189
|
+
* muss also ein Firebase-ID-Token sein — mit `apiKeyAuth` ist er nicht
|
|
190
|
+
* erreichbar. Ausserdem prueft das Backend die Kassenzuweisung hier im Rumpf
|
|
191
|
+
* (der Endpunkt laeuft mit `checkCashRegister: false`), ein Kassen-Benutzer
|
|
192
|
+
* bekommt also nur die ihm zugewiesenen Kassen.
|
|
193
|
+
*/
|
|
194
|
+
async function listMyReceipts(rufen, options) {
|
|
195
|
+
if (typeof options.cashregisterId !== 'string' || options.cashregisterId.trim() === '') {
|
|
196
|
+
throw new errors_js_1.KasseneckValidationError('listMyReceipts', 'cashregisterId fehlt', 'request');
|
|
197
|
+
}
|
|
198
|
+
if (options.limit !== undefined && (!Number.isInteger(options.limit) || options.limit < 1)) {
|
|
199
|
+
throw new errors_js_1.KasseneckValidationError('listMyReceipts', `limit muss eine ganze Zahl ab 1 sein, war "${options.limit}"`, 'request');
|
|
200
|
+
}
|
|
201
|
+
for (const feld of ['from', 'to']) {
|
|
202
|
+
const wert = options[feld];
|
|
203
|
+
if (wert !== undefined && !/^\d{4}-\d{2}-\d{2}/.test(wert)) {
|
|
204
|
+
throw new errors_js_1.KasseneckValidationError('listMyReceipts', `${feld} muss mit YYYY-MM-DD beginnen, war "${wert}"`, 'request');
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const daten = await rufen('listMyReceipts', {
|
|
208
|
+
cashregisterid: options.cashregisterId,
|
|
209
|
+
limit: options.limit,
|
|
210
|
+
...(options.from !== undefined ? { from: options.from } : {}),
|
|
211
|
+
...(options.to !== undefined ? { to: options.to } : {}),
|
|
212
|
+
});
|
|
213
|
+
const liste = daten?.receipts;
|
|
214
|
+
if (!Array.isArray(liste)) {
|
|
215
|
+
throw antwortfehler('listMyReceipts', 'Antwort enthaelt keine Belegliste (data.receipts fehlt)');
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
receipts: liste.map((eintrag) => (0, index_js_2.fromReceiptSummaryPayload)((typeof eintrag === 'object' && eintrag !== null ? eintrag : {}))),
|
|
219
|
+
stats: kennzahlen(daten?.stats),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Kennzahlen aus der Antwort. Sie duerfen Luecken haben, ohne die Belegliste
|
|
224
|
+
* unbrauchbar zu machen — eine fehlende Wochenreihe ist kein Grund, dem
|
|
225
|
+
* Kassier die Belege vorzuenthalten.
|
|
226
|
+
*/
|
|
227
|
+
function kennzahlen(roh) {
|
|
228
|
+
const quelle = (typeof roh === 'object' && roh !== null ? roh : {});
|
|
229
|
+
const tage = Array.isArray(quelle.days) ? quelle.days : [];
|
|
230
|
+
return {
|
|
231
|
+
today: {
|
|
232
|
+
revenueCents: (0, money_js_1.euroToCents)(quelle.today?.umsatz),
|
|
233
|
+
count: typeof quelle.today?.count === 'number' ? quelle.today.count : 0,
|
|
234
|
+
},
|
|
235
|
+
trendPercent: typeof quelle.trendPct === 'number' ? quelle.trendPct : null,
|
|
236
|
+
days: tage.map((tag) => {
|
|
237
|
+
const eintrag = (typeof tag === 'object' && tag !== null ? tag : {});
|
|
238
|
+
return {
|
|
239
|
+
date: typeof eintrag.date === 'string' ? eintrag.date : '',
|
|
240
|
+
revenueCents: (0, money_js_1.euroToCents)(eintrag.umsatz),
|
|
241
|
+
};
|
|
242
|
+
}),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
/** Einzelnen Beleg der angemeldeten Kasse holen. */
|
|
246
|
+
async function getReceipt(rufen, receiptId) {
|
|
247
|
+
return belegAusHuelle(await rufen('getReceipt', { receiptId }), 'getReceipt');
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Wie [getReceipt], liefert zusaetzlich die Firmen-/Druckdaten aus derselben
|
|
251
|
+
* Antwort (Firma, Anschrift, Steuernummer, UID, Fusszeilen, Logo-Adresse,
|
|
252
|
+
* Kleinunternehmer-Kennzeichen) — die Angaben, die ein Beleg im Kopf und Fuss
|
|
253
|
+
* traegt (siehe models/receipt-company.ts).
|
|
254
|
+
*/
|
|
255
|
+
async function getReceiptWithCompany(rufen, receiptId) {
|
|
256
|
+
return belegMitFirmaAusHuelle(await rufen('getReceipt', { receiptId }), 'getReceipt');
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Verschluesselte Volltext-Belegnummer erzeugen — der Bezeichner, unter dem der
|
|
260
|
+
* Beleg oeffentlich abrufbar ist (Beleg-Download, Pruefportal).
|
|
261
|
+
*/
|
|
262
|
+
async function generateFullReceiptId(rufen, receiptId) {
|
|
263
|
+
const daten = await rufen('generateFullReceiptId', { receiptId });
|
|
264
|
+
const id = daten?.fullReceiptId;
|
|
265
|
+
if (typeof id !== 'string') {
|
|
266
|
+
throw antwortfehler('generateFullReceiptId', 'Antwort enthaelt keine fullReceiptId');
|
|
267
|
+
}
|
|
268
|
+
return id;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Berichtsmonat des allerersten Belegs dieser Kasse — die untere Grenze aller
|
|
272
|
+
* Monatsberichte.
|
|
273
|
+
*
|
|
274
|
+
* **Nicht fuer den Kassen-Benutzer-Weg (`registerUserAuth`):** dieser Endpunkt
|
|
275
|
+
* fuehrt kein `allowRegisterUser`, das Backend weist die Browser-Kasse hier ab
|
|
276
|
+
* (siehe Modulkommentar oben). Mit `apiKeyAuth` ist er offen.
|
|
277
|
+
*/
|
|
278
|
+
async function getFirstReceiptDate(rufen) {
|
|
279
|
+
const roh = await rufen('getFirstReceiptDate');
|
|
280
|
+
if (typeof roh !== 'string') {
|
|
281
|
+
throw antwortfehler('getFirstReceiptDate', 'Antwort enthaelt keinen Zeitstempel');
|
|
282
|
+
}
|
|
283
|
+
// Ueber die Wiener Wanduhrzeit statt ueber getMonth(): der erste Beleg eines
|
|
284
|
+
// Monats liegt gern kurz nach Mitternacht, und der eingebaute Monat waere der
|
|
285
|
+
// des ausfuehrenden Rechners (siehe vienna-time.ts).
|
|
286
|
+
//
|
|
287
|
+
// Die Deutung wirft ein gewoehnliches Error, wenn der Zeitstempel unlesbar
|
|
288
|
+
// ist. Das ist hier ein Antwortproblem und gehoert in die Fehler-Union, die
|
|
289
|
+
// dieser Endpunkt zusagt — sonst faellt der Aufrufer aus allen Waechtern.
|
|
290
|
+
try {
|
|
291
|
+
const wanduhr = (0, vienna_time_js_1.toViennaWallClock)((0, vienna_time_js_1.parseServerTimeStamp)(roh));
|
|
292
|
+
return { month: wanduhr.month, year: wanduhr.year };
|
|
293
|
+
}
|
|
294
|
+
catch {
|
|
295
|
+
// Der Zeitstempel selbst wandert NICHT in die Meldung: er kommt aus einer
|
|
296
|
+
// fremden Antwort, und was dort steht, ist nicht unsere Zusage.
|
|
297
|
+
throw antwortfehler('getFirstReceiptDate', 'Antwort enthaelt keinen lesbaren Zeitstempel');
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Prueft die Gutschein-Kombination eines Belegs und liefert den ersten
|
|
302
|
+
* Regelverstoss als Text (oder `null`) — Zwilling von
|
|
303
|
+
* `checkVoucherCombinationError`. Bewusst als Rueckgabewert statt als Fehler:
|
|
304
|
+
* eine Kassenoberflaeche will das pruefen, **bevor** sie den Beleg abschickt.
|
|
305
|
+
*/
|
|
306
|
+
function checkVoucherCombinationError(vouchers, items) {
|
|
307
|
+
let einloesenWert = 0;
|
|
308
|
+
let verkaufenWert = 0;
|
|
309
|
+
let einloesenPromo = 0;
|
|
310
|
+
let verkaufenPromo = 0;
|
|
311
|
+
for (const voucher of vouchers) {
|
|
312
|
+
if (voucher.type === index_js_1.VoucherType.value && voucher.action === index_js_1.VoucherAction.redeem) {
|
|
313
|
+
einloesenWert++;
|
|
314
|
+
}
|
|
315
|
+
else if (voucher.type === index_js_1.VoucherType.value && voucher.action === index_js_1.VoucherAction.sell) {
|
|
316
|
+
verkaufenWert++;
|
|
317
|
+
}
|
|
318
|
+
else if (voucher.type === index_js_1.VoucherType.promo && voucher.action === index_js_1.VoucherAction.redeem) {
|
|
319
|
+
einloesenPromo++;
|
|
320
|
+
}
|
|
321
|
+
else if (voucher.type === index_js_1.VoucherType.promo && voucher.action === index_js_1.VoucherAction.sell) {
|
|
322
|
+
verkaufenPromo++;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
const einloesenGesamt = einloesenWert + einloesenPromo;
|
|
326
|
+
const verkaufenGesamt = verkaufenWert + verkaufenPromo;
|
|
327
|
+
if (verkaufenPromo > 0) {
|
|
328
|
+
return 'Ungueltige Daten: Gutscheine mit type promo duerfen nicht verkauft werden';
|
|
329
|
+
}
|
|
330
|
+
if (einloesenPromo > 1) {
|
|
331
|
+
return 'Ungueltige Daten: Es darf nur ein Gutschein mit type promo eingeloest werden';
|
|
332
|
+
}
|
|
333
|
+
if (einloesenPromo > 0 && einloesenGesamt > 1) {
|
|
334
|
+
return 'Ungueltige Daten: Ein Gutschein mit type promo darf nicht mit anderen Gutscheinen kombiniert werden';
|
|
335
|
+
}
|
|
336
|
+
if (einloesenPromo > 0 && verkaufenGesamt > 0) {
|
|
337
|
+
return 'Ungueltige Daten: Mit einem Gutschein mit type promo duerfen nicht andere Gutscheine verkauft werden';
|
|
338
|
+
}
|
|
339
|
+
if (einloesenGesamt > 0 && items.length === 0) {
|
|
340
|
+
return 'Ungueltige Daten: Gutscheine mit action redeem benoetigen mindestens ein item';
|
|
341
|
+
}
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Belegtyp aufloesen. Anders als bei der Zahlungsart bleibt es hier streng:
|
|
346
|
+
* den Belegtyp setzt kein Aufrufer aus Serverdaten, er kommt aus einem der
|
|
347
|
+
* benannten Aufrufe — ein unbekannter Wert waere ein Programmierfehler.
|
|
348
|
+
*/
|
|
349
|
+
function belegtyp(wert) {
|
|
350
|
+
if (typeof wert === 'object') {
|
|
351
|
+
return wert;
|
|
352
|
+
}
|
|
353
|
+
if (!Object.prototype.hasOwnProperty.call(index_js_1.ReceiptType, wert)) {
|
|
354
|
+
throw eingabefehler(`Belegtyp: unbekannter Schluessel "${wert}"`);
|
|
355
|
+
}
|
|
356
|
+
return index_js_1.ReceiptType[wert];
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Wandelt Positionen/Gutscheine in ihre Nutzlast und faengt dabei die strengen
|
|
360
|
+
* Schreibpfad-Pruefungen der Modelle ab (unbekannter Steuersatz, unbekannte
|
|
361
|
+
* Gutschein-Aktion). Die Modelle werfen dort ein nacktes `Error`; hier soll
|
|
362
|
+
* nur die Fehler-Union des Pakets herauskommen, damit ein Verbraucher, der
|
|
363
|
+
* nach den Waechtern verzweigt, nicht im "unbekannt"-Zweig landet.
|
|
364
|
+
*/
|
|
365
|
+
function alsNutzlast(werte, wandeln) {
|
|
366
|
+
try {
|
|
367
|
+
return werte.map(wandeln);
|
|
368
|
+
}
|
|
369
|
+
catch (ursache) {
|
|
370
|
+
// Die Meldungen der Modelle sind vom Paket formuliert und geheimnisfrei
|
|
371
|
+
// (sie nennen den unbekannten Steuersatz bzw. Schluessel, sonst nichts).
|
|
372
|
+
throw eingabefehler(ursache instanceof Error ? ursache.message : 'Ungueltige Nutzlast uebergeben.');
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
/** Zahlungsart des Aufrufers pruefen — unbekannt wirft, bevor etwas rausgeht. */
|
|
376
|
+
function gepruefteZahlungsart(wert) {
|
|
377
|
+
if (typeof wert === 'object') {
|
|
378
|
+
return wert.value;
|
|
379
|
+
}
|
|
380
|
+
if (!Object.prototype.hasOwnProperty.call(index_js_1.KeckPaymentMethod, wert)) {
|
|
381
|
+
throw eingabefehler(`Zahlungsart: unbekannter Schluessel "${wert}"`);
|
|
382
|
+
}
|
|
383
|
+
return index_js_1.KeckPaymentMethod[wert].value;
|
|
384
|
+
}
|
|
385
|
+
/** Kartenanbieter pruefen — er stammt vom Aufrufer, nicht aus Serverdaten. */
|
|
386
|
+
function kartenanbieter(wert) {
|
|
387
|
+
if (!Object.prototype.hasOwnProperty.call(index_js_1.CreditCardProvider, wert)) {
|
|
388
|
+
throw eingabefehler(`Kartenanbieter: unbekannter Schluessel "${wert}"`);
|
|
389
|
+
}
|
|
390
|
+
return wert;
|
|
391
|
+
}
|
|
392
|
+
/** Fehler in der Eingabe des Aufrufers — es geht keine Anfrage raus. */
|
|
393
|
+
function eingabefehler(grund) {
|
|
394
|
+
return new errors_js_1.KasseneckValidationError('createReceipt', grund, 'request');
|
|
395
|
+
}
|
|
396
|
+
/** Die Antwort meldete Erfolg, trug aber nicht, was der Aufruf zusagt. */
|
|
397
|
+
function antwortfehler(functionName, grund) {
|
|
398
|
+
return new errors_js_1.KasseneckValidationError(functionName, grund, 'response');
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* `createReceipt` und `getReceipt` liefern den Beleg unter `data.receipt`,
|
|
402
|
+
* daneben die Firmen-/Druckdaten (Firma, Anschrift, Fusszeilen). Diese Lesart
|
|
403
|
+
* nimmt nur den Beleg: die Druckdaten gehoeren nicht zum RKSV-Kernbeleg (siehe
|
|
404
|
+
* models/receipt.ts), und die bestehenden Aufrufe sollen ihre Zusage behalten.
|
|
405
|
+
* Wer beides braucht, nimmt [belegMitFirmaAusHuelle] ueber die
|
|
406
|
+
* `…WithCompany`-Varianten.
|
|
407
|
+
*/
|
|
408
|
+
function belegAusHuelle(daten, functionName) {
|
|
409
|
+
const huelle = daten;
|
|
410
|
+
if (huelle == null || typeof huelle !== 'object' || huelle.receipt == null) {
|
|
411
|
+
throw antwortfehler(functionName, 'Antwort enthaelt keinen Beleg (data.receipt fehlt)');
|
|
412
|
+
}
|
|
413
|
+
const beleg = huelle.receipt;
|
|
414
|
+
if (typeof beleg !== 'object' || Array.isArray(beleg)) {
|
|
415
|
+
throw antwortfehler(functionName, 'Antwort enthaelt keinen Beleg (data.receipt ist kein Objekt)');
|
|
416
|
+
}
|
|
417
|
+
// Positionen und Gutscheine werden gleich mit `.map` gelesen. Eine Antwort,
|
|
418
|
+
// die dort etwas anderes als eine Liste fuehrt, ergab bis hierher einen
|
|
419
|
+
// nackten TypeError ("… .map is not a function") und fiel damit aus der
|
|
420
|
+
// Fehler-Union. Fehlend und `null` bleiben erlaubt: Nullbelege haben keine
|
|
421
|
+
// Positionen.
|
|
422
|
+
const roh = beleg;
|
|
423
|
+
for (const feld of ['items', 'vouchers']) {
|
|
424
|
+
const wert = roh[feld];
|
|
425
|
+
if (wert != null && !Array.isArray(wert)) {
|
|
426
|
+
throw antwortfehler(functionName, `Antwort enthaelt einen Beleg mit unbrauchbarem Feld "${feld}"`);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
return (0, index_js_2.fromReceiptPayload)(beleg);
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Beleg **und** Firmendaten aus derselben Huelle. Der Beleg entscheidet:
|
|
433
|
+
* fehlt er, ist die Antwort unbrauchbar. Die Firmendaten duerfen dagegen
|
|
434
|
+
* luecken haben — ein Kundendokument ohne gepflegte Fusszeile ist kein Grund,
|
|
435
|
+
* einen ausgestellten Beleg nicht anzuzeigen (siehe models/receipt-company.ts).
|
|
436
|
+
*/
|
|
437
|
+
function belegMitFirmaAusHuelle(daten, functionName) {
|
|
438
|
+
const receipt = belegAusHuelle(daten, functionName);
|
|
439
|
+
const d = (daten ?? {});
|
|
440
|
+
const layout = d.layout && typeof d.layout === 'object' && Array.isArray(d.layout.lines) ? d.layout : null;
|
|
441
|
+
const pa = d.pruefangaben && typeof d.pruefangaben === 'object' ? d.pruefangaben : null;
|
|
442
|
+
const text = (v) => (typeof v === 'string' && v ? v : null);
|
|
443
|
+
return {
|
|
444
|
+
receipt,
|
|
445
|
+
company: (0, index_js_2.fromReceiptCompanyPayload)(daten),
|
|
446
|
+
testKasse: d.testKasse === true,
|
|
447
|
+
testSignatur: d.testSignatur === true,
|
|
448
|
+
kopfId: typeof d.kopfId === 'string' ? d.kopfId : null,
|
|
449
|
+
layout,
|
|
450
|
+
pruefangaben: pa ? { karteRegistriertAm: text(pa.karteRegistriertAm), kasseRegistriertAm: text(pa.kasseRegistriertAm) } : null,
|
|
451
|
+
};
|
|
452
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ReportMonth } from '../models/index.js';
|
|
2
|
+
import type { KasseneckBinaryTransport } from './transport.js';
|
|
3
|
+
/**
|
|
4
|
+
* Bericht-Downloads — Zwilling von `downloadDailyReport`/`downloadMonthlyReport`
|
|
5
|
+
* in kasseneck_api/lib/kasseneck_api.dart (Zeilen 113-128).
|
|
6
|
+
*
|
|
7
|
+
* **Beide liefern ein PDF, also Binaerdaten.** Das Flutter-Vorbild liest die
|
|
8
|
+
* Antwort als Zeichenkette und nimmt davon `codeUnits`; in JavaScript waere das
|
|
9
|
+
* schlicht falsch — `response.text()` deutet die Bytes als UTF-8 und ersetzt
|
|
10
|
+
* jedes Byte ueber 0x7F durch U+FFFD. Ein so "heruntergeladener" Tagesbericht
|
|
11
|
+
* liesse sich in keinem Betrachter oeffnen. Dieses Paket weicht daher bewusst
|
|
12
|
+
* ab: es liest `arrayBuffer()` und liefert `Uint8Array` (siehe
|
|
13
|
+
* [createBinaryTransport] in transport.ts).
|
|
14
|
+
*
|
|
15
|
+
* **Kassen-Benutzer-Weg (`registerUserAuth`, Browser-Kasse):** Keiner der
|
|
16
|
+
* beiden Download-Endpunkte setzt `allowRegisterUser`; sie funktionieren nur
|
|
17
|
+
* mit `apiKeyAuth`. Dieses Paket bildet das **nicht** nach; wer darf,
|
|
18
|
+
* entscheidet allein das Backend. Der Hinweis steht hier, damit ein Leser
|
|
19
|
+
* nicht raten muss.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Tagesbericht als PDF.
|
|
23
|
+
*
|
|
24
|
+
* Der Kalendertag wird nach **Wiener** Wanduhrzeit bestimmt, nicht nach der
|
|
25
|
+
* Zeitzone des ausfuehrenden Rechners: der Geschaeftstag ist ein
|
|
26
|
+
* oesterreichischer Kalenderwert. Ein Zeitpunkt vom 1. Maerz 00:30 Wiener Zeit
|
|
27
|
+
* gehoert in den Tagesbericht vom 1. Maerz — die eingebauten
|
|
28
|
+
* `getDate()`/`getMonth()` wuerden auf einer UTC-Maschine den Bericht des
|
|
29
|
+
* Vortags holen (das Dart-Vorbild nimmt hier die Geraetezeit, was auf einer
|
|
30
|
+
* oesterreichischen Kasse zufaellig stimmt).
|
|
31
|
+
*/
|
|
32
|
+
export declare function downloadDailyReport(rufen: KasseneckBinaryTransport, date: Date): Promise<Uint8Array>;
|
|
33
|
+
/**
|
|
34
|
+
* Monatsbericht als PDF.
|
|
35
|
+
*
|
|
36
|
+
* **Der Endpunkt heisst `downloadReport`**, nicht `downloadMonthlyReport` —
|
|
37
|
+
* Methodenname und Endpunktname fallen hier auseinander (so im Dart-Vorbild und
|
|
38
|
+
* so im Backend, `report-endpoints.js`).
|
|
39
|
+
*
|
|
40
|
+
* `month` geht als **Zahl 1-12** raus (im Flutter-Paket `reportMonth.month.id`,
|
|
41
|
+
* wo `KeckMonth.january.id === 1` ist) — kein Name, kein nullbasierter Index.
|
|
42
|
+
*/
|
|
43
|
+
export declare function downloadMonthlyReport(rufen: KasseneckBinaryTransport, reportMonth: ReportMonth): Promise<Uint8Array>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.downloadDailyReport = downloadDailyReport;
|
|
4
|
+
exports.downloadMonthlyReport = downloadMonthlyReport;
|
|
5
|
+
const vienna_time_js_1 = require("../vienna-time.js");
|
|
6
|
+
const errors_js_1 = require("./errors.js");
|
|
7
|
+
/**
|
|
8
|
+
* Bericht-Downloads — Zwilling von `downloadDailyReport`/`downloadMonthlyReport`
|
|
9
|
+
* in kasseneck_api/lib/kasseneck_api.dart (Zeilen 113-128).
|
|
10
|
+
*
|
|
11
|
+
* **Beide liefern ein PDF, also Binaerdaten.** Das Flutter-Vorbild liest die
|
|
12
|
+
* Antwort als Zeichenkette und nimmt davon `codeUnits`; in JavaScript waere das
|
|
13
|
+
* schlicht falsch — `response.text()` deutet die Bytes als UTF-8 und ersetzt
|
|
14
|
+
* jedes Byte ueber 0x7F durch U+FFFD. Ein so "heruntergeladener" Tagesbericht
|
|
15
|
+
* liesse sich in keinem Betrachter oeffnen. Dieses Paket weicht daher bewusst
|
|
16
|
+
* ab: es liest `arrayBuffer()` und liefert `Uint8Array` (siehe
|
|
17
|
+
* [createBinaryTransport] in transport.ts).
|
|
18
|
+
*
|
|
19
|
+
* **Kassen-Benutzer-Weg (`registerUserAuth`, Browser-Kasse):** Keiner der
|
|
20
|
+
* beiden Download-Endpunkte setzt `allowRegisterUser`; sie funktionieren nur
|
|
21
|
+
* mit `apiKeyAuth`. Dieses Paket bildet das **nicht** nach; wer darf,
|
|
22
|
+
* entscheidet allein das Backend. Der Hinweis steht hier, damit ein Leser
|
|
23
|
+
* nicht raten muss.
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Tagesbericht als PDF.
|
|
27
|
+
*
|
|
28
|
+
* Der Kalendertag wird nach **Wiener** Wanduhrzeit bestimmt, nicht nach der
|
|
29
|
+
* Zeitzone des ausfuehrenden Rechners: der Geschaeftstag ist ein
|
|
30
|
+
* oesterreichischer Kalenderwert. Ein Zeitpunkt vom 1. Maerz 00:30 Wiener Zeit
|
|
31
|
+
* gehoert in den Tagesbericht vom 1. Maerz — die eingebauten
|
|
32
|
+
* `getDate()`/`getMonth()` wuerden auf einer UTC-Maschine den Bericht des
|
|
33
|
+
* Vortags holen (das Dart-Vorbild nimmt hier die Geraetezeit, was auf einer
|
|
34
|
+
* oesterreichischen Kasse zufaellig stimmt).
|
|
35
|
+
*/
|
|
36
|
+
// `async`, damit auch die Eingabepruefung als abgelehntes Versprechen ankommt
|
|
37
|
+
// und nicht als synchroner Wurf am `await` des Aufrufers vorbei.
|
|
38
|
+
async function downloadDailyReport(rufen, date) {
|
|
39
|
+
let wanduhr;
|
|
40
|
+
try {
|
|
41
|
+
wanduhr = (0, vienna_time_js_1.toViennaWallClock)(date);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Ein Invalid Date ergaebe sonst `{year: null, month: null, day: null}` im
|
|
45
|
+
// Rumpf (JSON.stringify macht aus NaN null) und einen ratlosen Serverfehler.
|
|
46
|
+
throw eingabefehler('downloadDailyReport', 'Uebergebener Zeitpunkt ist unbrauchbar (Invalid Date)');
|
|
47
|
+
}
|
|
48
|
+
return rufen('downloadDailyReport', { year: wanduhr.year, month: wanduhr.month, day: wanduhr.day });
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Monatsbericht als PDF.
|
|
52
|
+
*
|
|
53
|
+
* **Der Endpunkt heisst `downloadReport`**, nicht `downloadMonthlyReport` —
|
|
54
|
+
* Methodenname und Endpunktname fallen hier auseinander (so im Dart-Vorbild und
|
|
55
|
+
* so im Backend, `report-endpoints.js`).
|
|
56
|
+
*
|
|
57
|
+
* `month` geht als **Zahl 1-12** raus (im Flutter-Paket `reportMonth.month.id`,
|
|
58
|
+
* wo `KeckMonth.january.id === 1` ist) — kein Name, kein nullbasierter Index.
|
|
59
|
+
*/
|
|
60
|
+
async function downloadMonthlyReport(rufen, reportMonth) {
|
|
61
|
+
const { month, year } = reportMonth;
|
|
62
|
+
if (!Number.isInteger(month) || month < 1 || month > 12) {
|
|
63
|
+
throw eingabefehler('downloadReport', `Berichtsmonat: month muss 1-12 sein, war "${month}"`);
|
|
64
|
+
}
|
|
65
|
+
if (!Number.isInteger(year)) {
|
|
66
|
+
throw eingabefehler('downloadReport', `Berichtsmonat: year muss eine ganze Zahl sein, war "${year}"`);
|
|
67
|
+
}
|
|
68
|
+
return rufen('downloadReport', { month, year });
|
|
69
|
+
}
|
|
70
|
+
/** Fehler in der Eingabe des Aufrufers — es geht keine Anfrage raus. */
|
|
71
|
+
function eingabefehler(functionName, grund) {
|
|
72
|
+
return new errors_js_1.KasseneckValidationError(functionName, grund, 'request');
|
|
73
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { KasseneckTransport } from './transport.js';
|
|
2
|
+
/**
|
|
3
|
+
* Betriebsstatus von Kasse und Signatureinheit bei FinanzOnline — Zwilling von
|
|
4
|
+
* `getCashboxStatus`/`getSignatureStatus` in
|
|
5
|
+
* kasseneck_api/lib/kasseneck_api.dart (Zeilen 410-440).
|
|
6
|
+
*
|
|
7
|
+
* Beide laufen ueber den **einen** Backend-Endpunkt `financeWebService`, der
|
|
8
|
+
* seine Vorgangsart als `method` **neben** `params` im Rumpf erwartet (so das
|
|
9
|
+
* Dart-Vorbild `_financeWebServicePostRequest`, so die Auswertung `b.method` im
|
|
10
|
+
* Backend). Die Antwort ist die uebliche Erfolgshuelle; darin liegt die
|
|
11
|
+
* FinanzOnline-Meldung unter `data.rkdbMessage`.
|
|
12
|
+
*
|
|
13
|
+
* **Kassen-Benutzer-Weg (`registerUserAuth`, Browser-Kasse):**
|
|
14
|
+
* `financeWebService` setzt kein `allowRegisterUser`; beide Abfragen
|
|
15
|
+
* funktionieren nur mit `apiKeyAuth`. Dieses Paket bildet das **nicht** nach —
|
|
16
|
+
* wer darf, entscheidet allein das Backend.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Betriebsstatus, den FinanzOnline meldet. Die vier bekannten Werte sind
|
|
20
|
+
* benannt; ein noch unbekannter Wert kommt **unveraendert** durch (`string`),
|
|
21
|
+
* statt wie im Dart-Vorbild still zu `null` zu werden. Lesen ist in diesem
|
|
22
|
+
* Paket tolerant: "unbekannter Status" und "kein Status" duerfen fuer den
|
|
23
|
+
* Aufrufer nicht dasselbe sein, sonst meldet eine Kasse mit einem neuen
|
|
24
|
+
* FON-Status genauso wie eine ohne Antwort.
|
|
25
|
+
*/
|
|
26
|
+
export type CashboxStatus = 'AKTIVIERT' | 'REGISTRIERT' | 'IN_BETRIEB' | 'AUSFALL' | (string & {});
|
|
27
|
+
/**
|
|
28
|
+
* Status der Signatureinheit. Wie [CashboxStatus], zusaetzlich der
|
|
29
|
+
* **abgeleitete** Wert `NOT_REGISTERED`: er ist kein FON-Status, sondern die
|
|
30
|
+
* Uebersetzung des Returncodes `B33` ("Signatureinheit nicht registriert").
|
|
31
|
+
*/
|
|
32
|
+
export type SignatureStatus = CashboxStatus | 'NOT_REGISTERED';
|
|
33
|
+
/** Betriebsstatus der Kasse bei FinanzOnline. */
|
|
34
|
+
export declare function getCashboxStatus(rufen: KasseneckTransport): Promise<CashboxStatus>;
|
|
35
|
+
/**
|
|
36
|
+
* Status der Signatureinheit mit der Zertifikatsseriennummer [zertifikatNrHex]
|
|
37
|
+
* (hexadezimal, z. B. `6F0404F0`).
|
|
38
|
+
*
|
|
39
|
+
* **Der Returncode wird vor dem Status gelesen** (wie im Dart-Vorbild): `B33`
|
|
40
|
+
* heisst "nicht registriert" und schlaegt jedes Statusfeld, das daneben stehen
|
|
41
|
+
* mag. Andersherum meldete eine nie registrierte Karte am Ende "in Betrieb".
|
|
42
|
+
*/
|
|
43
|
+
export declare function getSignatureStatus(rufen: KasseneckTransport, zertifikatNrHex: string): Promise<SignatureStatus>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getCashboxStatus = getCashboxStatus;
|
|
4
|
+
exports.getSignatureStatus = getSignatureStatus;
|
|
5
|
+
const errors_js_1 = require("./errors.js");
|
|
6
|
+
/**
|
|
7
|
+
* Vorgangsnamen, unter denen Fehler dieser beiden Abfragen erscheinen. Beide
|
|
8
|
+
* laufen ueber denselben Endpunkt `financeWebService`; ein Fehler, der nur den
|
|
9
|
+
* Endpunkt nennt, verschweigt dem Aufrufer, ob der Kassen- oder der
|
|
10
|
+
* Signaturstatus scheiterte. Der Transport bildet denselben Namen aus
|
|
11
|
+
* `<funktion>/<method>` — hier stehen die Konstanten fuer die Fehler, die schon
|
|
12
|
+
* vor dem Senden entstehen.
|
|
13
|
+
*/
|
|
14
|
+
const VORGANG_KASSE = 'financeWebService/status_cashbox';
|
|
15
|
+
const VORGANG_SIGNATUR = 'financeWebService/status_signature';
|
|
16
|
+
/** Betriebsstatus der Kasse bei FinanzOnline. */
|
|
17
|
+
async function getCashboxStatus(rufen) {
|
|
18
|
+
const daten = await rufen('financeWebService', {}, { method: 'status_cashbox' });
|
|
19
|
+
return statusAusMeldung(daten, VORGANG_KASSE);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Status der Signatureinheit mit der Zertifikatsseriennummer [zertifikatNrHex]
|
|
23
|
+
* (hexadezimal, z. B. `6F0404F0`).
|
|
24
|
+
*
|
|
25
|
+
* **Der Returncode wird vor dem Status gelesen** (wie im Dart-Vorbild): `B33`
|
|
26
|
+
* heisst "nicht registriert" und schlaegt jedes Statusfeld, das daneben stehen
|
|
27
|
+
* mag. Andersherum meldete eine nie registrierte Karte am Ende "in Betrieb".
|
|
28
|
+
*/
|
|
29
|
+
async function getSignatureStatus(rufen, zertifikatNrHex) {
|
|
30
|
+
if (typeof zertifikatNrHex !== 'string' || !zertifikatNrHex.trim()) {
|
|
31
|
+
throw new errors_js_1.KasseneckValidationError(VORGANG_SIGNATUR, 'zertifikatNrHex fehlt', 'request');
|
|
32
|
+
}
|
|
33
|
+
const daten = await rufen('financeWebService', { zertifikatnr_hex: zertifikatNrHex }, { method: 'status_signature' });
|
|
34
|
+
if (daten?.rkdbMessage?.rc === 'B33') {
|
|
35
|
+
return 'NOT_REGISTERED';
|
|
36
|
+
}
|
|
37
|
+
return statusAusMeldung(daten, VORGANG_SIGNATUR);
|
|
38
|
+
}
|
|
39
|
+
function statusAusMeldung(daten, functionName) {
|
|
40
|
+
const status = daten?.rkdbMessage?.status;
|
|
41
|
+
if (typeof status !== 'string' || !status) {
|
|
42
|
+
// Der Inhalt der Antwort wandert NICHT in die Meldung — er kommt von einer
|
|
43
|
+
// fremden Stelle, und was dort steht, ist nicht unsere Zusage.
|
|
44
|
+
throw new errors_js_1.KasseneckValidationError(functionName, 'Antwort enthaelt keinen Status (data.rkdbMessage.status)', 'response');
|
|
45
|
+
}
|
|
46
|
+
return status;
|
|
47
|
+
}
|