@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,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unterpfad `@kreiseck/kasseneck-api/register` — die **Anmeldung der
|
|
3
|
+
* Browser-Kasse**: ein Geraet koppeln, seine Kassen-Benutzer auflisten, einen
|
|
4
|
+
* davon per PIN anmelden (mit oder ohne Benutzerauswahl), und die entstandene
|
|
5
|
+
* Sitzung erneuern bzw. beenden.
|
|
6
|
+
*
|
|
7
|
+
* Diese Aufrufe stehen vor allen anderen: ohne sie gibt es keine
|
|
8
|
+
* Identitaet, mit der ein Beleg entstehen koennte.
|
|
9
|
+
*
|
|
10
|
+
* **Sie zerfallen in zwei Haelften, und der Unterschied ist wesentlich:**
|
|
11
|
+
*
|
|
12
|
+
* | Aufruf | Anmeldung |
|
|
13
|
+
* |---|---|
|
|
14
|
+
* | [pairRegisterDevice] | **keine** — der Kopplungs-Code ist der Nachweis |
|
|
15
|
+
* | [listRegisterUsersForDevice] | **keine** — der Ausweis des Geraets ist der Nachweis |
|
|
16
|
+
* | [unpairRegisterDevice] | **keine** — der Ausweis des Geraets; sperrt es im Backend (Entkoppeln) |
|
|
17
|
+
* | [registerUserLogin] | **keine** — dieser Aufruf erzeugt sie |
|
|
18
|
+
* | [registerPinLogin] | **keine** — wie registerUserLogin, nur ohne Benutzerauswahl (Geraete-Modus `pin`) |
|
|
19
|
+
* | [renewRegisterSession] | Kassen-Benutzer (`registerUserAuth`) |
|
|
20
|
+
* | [endRegisterSession] | Kassen-Benutzer (`registerUserAuth`) |
|
|
21
|
+
*
|
|
22
|
+
* Die ersten drei nehmen deshalb **keinen Transport** entgegen, sondern nur
|
|
23
|
+
* die Verbindungsangaben, und bauen ihn selbst — die anmeldungsfreie Anmeldung
|
|
24
|
+
* dahinter wird bewusst nicht exportiert, sonst liesse sich damit jeder Aufruf
|
|
25
|
+
* des Pakets ohne Anmeldung bauen (ausfuehrlich in pairing.ts). Die letzten
|
|
26
|
+
* beiden nehmen den Transport wie jeder andere Endpunkt-Aufruf und stehen
|
|
27
|
+
* zusaetzlich in `createKasseneckApi`.
|
|
28
|
+
*
|
|
29
|
+
* Der uebliche Ablauf einer Browser-Kasse:
|
|
30
|
+
*
|
|
31
|
+
* ```ts
|
|
32
|
+
* import {
|
|
33
|
+
* pairRegisterDevice, listRegisterUsersForDevice, registerUserLogin,
|
|
34
|
+
* } from '@kreiseck/kasseneck-api/register';
|
|
35
|
+
*
|
|
36
|
+
* // Einmalig: Code aus dem Panel gegen den Geraeteausweis tauschen.
|
|
37
|
+
* const geraet = await pairRegisterDevice({ code: 'K7NPQR34', label: 'Schank' });
|
|
38
|
+
*
|
|
39
|
+
* // Bei jedem Schichtwechsel: auswaehlen und per PIN anmelden.
|
|
40
|
+
* const { users } = await listRegisterUsersForDevice(geraet);
|
|
41
|
+
* const sitzung = await registerUserLogin({
|
|
42
|
+
* ...geraet, userId: users[0]!.id, pin: '1234', cashregisterId: geraet.cashregisterId,
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* Mit `sitzung.customToken` meldet sich der Verbraucher bei Firebase an; das
|
|
47
|
+
* daraus entstehende ID-Token und `sitzung.sessionId` ergeben zusammen
|
|
48
|
+
* `registerUserAuth` — ab da laeuft alles Weitere ueber den ueblichen Weg.
|
|
49
|
+
*/
|
|
50
|
+
export { pairRegisterDevice, listRegisterUsersForDevice, unpairRegisterDevice, registerUserLogin, registerPinLogin, } from './pairing.js';
|
|
51
|
+
export { renewRegisterSession, endRegisterSession } from './session.js';
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { type TransportOptions } from '../client/transport.js';
|
|
2
|
+
import { type ReceiptCompany } from '../models/receipt-company.js';
|
|
3
|
+
import { type KasseSettings } from '../kasse/settings.js';
|
|
4
|
+
/**
|
|
5
|
+
* Verbindungsangaben ohne Anmeldung — alles, was [TransportOptions] ausser der
|
|
6
|
+
* Anmeldung fuehrt. Alle Felder sind wahlfrei: ohne Angabe gelten Basis-URL und
|
|
7
|
+
* Zeitlimit der Produktion und das globale `fetch`.
|
|
8
|
+
*/
|
|
9
|
+
export type RegisterDeviceConnection = Omit<TransportOptions, 'auth'>;
|
|
10
|
+
/** Ausweis eines gekoppelten Geraets — Nachweis der beiden Folgeaufrufe. */
|
|
11
|
+
export interface RegisterDeviceCredentials {
|
|
12
|
+
/** Kunde, unter dem das Geraet haengt (aus der Kopplung). */
|
|
13
|
+
ownerUid: string;
|
|
14
|
+
/** Dieses Geraet (aus der Kopplung). */
|
|
15
|
+
deviceId: string;
|
|
16
|
+
/** Geheimnis dieses Geraets; das Backend liefert es genau einmal aus. */
|
|
17
|
+
deviceSecret: string;
|
|
18
|
+
}
|
|
19
|
+
/** Was das Geraet ueber sich sagt -- fuer das Panel (welches Geraet ist das?). Alles optional. */
|
|
20
|
+
export interface RegisterClientInfo {
|
|
21
|
+
userAgent?: string;
|
|
22
|
+
platform?: string;
|
|
23
|
+
language?: string;
|
|
24
|
+
/** IANA-Zeitzone, z. B. Europe/Vienna. */
|
|
25
|
+
tz?: string;
|
|
26
|
+
screen?: {
|
|
27
|
+
w: number;
|
|
28
|
+
h: number;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** Standort aus der Browser-Ortung (freiwillig); Grundlage der Standortsperre. */
|
|
32
|
+
export interface RegisterGeo {
|
|
33
|
+
lat: number;
|
|
34
|
+
lng: number;
|
|
35
|
+
/** Genauigkeit in Metern. */
|
|
36
|
+
acc?: number;
|
|
37
|
+
}
|
|
38
|
+
/** Angaben, die Kopplung und Login zusaetzlich mitschicken duerfen. */
|
|
39
|
+
export interface RegisterGeraeteAngaben {
|
|
40
|
+
client?: RegisterClientInfo;
|
|
41
|
+
geo?: RegisterGeo | null;
|
|
42
|
+
}
|
|
43
|
+
export interface PairRegisterDeviceOptions extends RegisterDeviceConnection, RegisterGeraeteAngaben {
|
|
44
|
+
/**
|
|
45
|
+
* Achtstelliger Kopplungs-Code aus dem Panel. Er ist 15 Minuten gueltig,
|
|
46
|
+
* genau **einmal** verwendbar und gilt fuer eine bestimmte Kasse.
|
|
47
|
+
*
|
|
48
|
+
* Gross-/Kleinschreibung und Leerzeichen an den Raendern sind gleichgueltig:
|
|
49
|
+
* das Backend beschneidet und schreibt gross. Dieses Paket prueft das Format
|
|
50
|
+
* **nicht** — es kennt das Alphabet nicht und wuerde eine spaetere Erweiterung
|
|
51
|
+
* ausschliessen.
|
|
52
|
+
*/
|
|
53
|
+
code: string;
|
|
54
|
+
/** Bezeichnung dieses Geraets in der Geraeteliste; ohne Angabe "Kasse". */
|
|
55
|
+
label?: string;
|
|
56
|
+
}
|
|
57
|
+
/** Ergebnis der Kopplung — der vollstaendige Ausweis dieses Geraets. */
|
|
58
|
+
export interface PairedRegisterDevice extends RegisterDeviceCredentials {
|
|
59
|
+
/** Kasse, an die die Kopplung dieses Geraet gebunden hat. */
|
|
60
|
+
cashregisterId: string;
|
|
61
|
+
/** Firmenname des Betriebs (Backend: `betrieb`) — Anzeige, kann leer sein. */
|
|
62
|
+
companyName: string;
|
|
63
|
+
/** Bezeichnung der Kasse (Backend: `kasse`) — Anzeige, kann leer sein. */
|
|
64
|
+
cashregisterLabel: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Art eines Kassen-Benutzers: eine Person oder ein Geraet (Sammelkonto). Ein
|
|
68
|
+
* kuenftiger, hier noch unbekannter Wert kommt unveraendert durch, statt still
|
|
69
|
+
* zu "person" zu werden — beim Lesen ist dieses Paket tolerant.
|
|
70
|
+
*/
|
|
71
|
+
export type RegisterUserKind = 'person' | 'device' | (string & {});
|
|
72
|
+
/** Ein Kassen-Benutzer, wie ihn der Anmeldebildschirm zeigt. */
|
|
73
|
+
export interface RegisterUserSummary {
|
|
74
|
+
id: string;
|
|
75
|
+
/** Anzeigename; kann leer sein. */
|
|
76
|
+
name: string;
|
|
77
|
+
kind: RegisterUserKind;
|
|
78
|
+
/**
|
|
79
|
+
* Die PIN dieses Benutzers wurde noch nicht unter der aktuellen Regel des
|
|
80
|
+
* Betriebs gesetzt: die Kasse zeigt ihm das Freifeld statt der Kaestchen.
|
|
81
|
+
* Das Backend sendet das Feld nur, wenn es zutrifft; gelesen ist es immer da.
|
|
82
|
+
*/
|
|
83
|
+
altbestand: boolean;
|
|
84
|
+
}
|
|
85
|
+
/** PIN-Regel des Betriebs — daraus baut die Kasse Kaestchen und Tastatur. */
|
|
86
|
+
export interface RegisterPinPolicy {
|
|
87
|
+
/** Feste Stellenzahl (Backend: 3 bis 6). */
|
|
88
|
+
stellen: number;
|
|
89
|
+
/** `ziffern` (nur 0-9) oder `zeichen` (0-9 plus Kopplungs-Alphabet). */
|
|
90
|
+
zeichen: 'ziffern' | 'zeichen' | (string & {});
|
|
91
|
+
}
|
|
92
|
+
/** Anmeldemodus des Geraets; ein unbekannter kuenftiger Wert kommt durch. */
|
|
93
|
+
export type RegisterLoginMode = 'auswahl' | 'pin' | (string & {});
|
|
94
|
+
/** Antwort von [listRegisterUsersForDevice]: Benutzer, Regel, Modus. */
|
|
95
|
+
export interface RegisterDeviceUsers {
|
|
96
|
+
/** Im Modus `pin` bewusst leer — Namen haben am nur-PIN-Geraet nichts verloren. */
|
|
97
|
+
users: RegisterUserSummary[];
|
|
98
|
+
/** Kassen-Einstellungen (betriebsweit + Geraet), gemischt mit den Standardwerten. */
|
|
99
|
+
settings: KasseSettings;
|
|
100
|
+
/** Belegkopf-Daten des Betriebs (Name, Anschrift, UID, Fusszeilen) -- ohne Geheimnisse. */
|
|
101
|
+
betriebsdaten: ReceiptCompany | null;
|
|
102
|
+
/**
|
|
103
|
+
* `null`, wenn das Backend (noch) keine Regel nennt — dann zeigt die Kasse
|
|
104
|
+
* das Freifeld, statt Kaestchen mit einer erratenen Stellenzahl.
|
|
105
|
+
*/
|
|
106
|
+
policy: RegisterPinPolicy | null;
|
|
107
|
+
loginMode: RegisterLoginMode;
|
|
108
|
+
/** Der Betrieb verlangt die Ortung beim Login (Standortsperre an). */
|
|
109
|
+
standortsperre: boolean;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Rechte eines Kassen-Benutzers (Backend: `perms`, Vorlagen `PERMS_KASSIER`
|
|
113
|
+
* und `PERMS_CHEF`). Der Inhaber kann einzelne Rechte abweichend setzen,
|
|
114
|
+
* deshalb sind weitere Schluessel zugelassen.
|
|
115
|
+
*
|
|
116
|
+
* **Ein fehlendes Recht gilt als nicht erteilt.** Die Oberflaeche soll im
|
|
117
|
+
* Zweifel weniger anbieten, nicht mehr; die tatsaechliche Grenze zieht ohnehin
|
|
118
|
+
* das Backend.
|
|
119
|
+
*/
|
|
120
|
+
/** Reichweite eines Rechts: keine | nur eigene Belege | alle. */
|
|
121
|
+
export type RegisterScope = 'none' | 'own' | 'all';
|
|
122
|
+
export interface RegisterUserPerms {
|
|
123
|
+
/** Belege ausstellen. */
|
|
124
|
+
sell: boolean;
|
|
125
|
+
/** Belege stornieren (Schalter, gespiegelt aus cancelScope !== 'none'). */
|
|
126
|
+
cancel: boolean;
|
|
127
|
+
/** Artikelstamm bearbeiten. */
|
|
128
|
+
articles: boolean;
|
|
129
|
+
/** Beleglayout/Kassen-Einstellungen bearbeiten (Chef). */
|
|
130
|
+
layout: boolean;
|
|
131
|
+
/** Berichte ansehen. */
|
|
132
|
+
reports: boolean;
|
|
133
|
+
/** Eine belegte Kasse uebernehmen (nur Kassen-Chef). */
|
|
134
|
+
takeover: boolean;
|
|
135
|
+
/** Storno-Reichweite; fehlt bei Altbestand (dann zaehlt `cancel`: true = all). */
|
|
136
|
+
cancelScope?: RegisterScope;
|
|
137
|
+
/** Belege ansehen; fehlt bei Altbestand (= all). */
|
|
138
|
+
receiptsScope?: RegisterScope;
|
|
139
|
+
/** Kassenlade ohne Verkauf oeffnen. */
|
|
140
|
+
drawer?: boolean;
|
|
141
|
+
/** Rabatt geben. */
|
|
142
|
+
discount?: boolean;
|
|
143
|
+
/** Trinkgeld anderen zuweisen. */
|
|
144
|
+
tipAssign?: boolean;
|
|
145
|
+
[weiteresRecht: string]: boolean | RegisterScope | undefined;
|
|
146
|
+
}
|
|
147
|
+
/** Reichweite lesen, mit der Migration des Backends (register-auth.js). */
|
|
148
|
+
export declare function cancelScopeOf(perms: RegisterUserPerms | null | undefined): RegisterScope;
|
|
149
|
+
export declare function receiptsScopeOf(perms: RegisterUserPerms | null | undefined): RegisterScope;
|
|
150
|
+
/** Der angemeldete Kassen-Benutzer. */
|
|
151
|
+
export interface RegisterUser {
|
|
152
|
+
id: string;
|
|
153
|
+
name: string;
|
|
154
|
+
perms: RegisterUserPerms;
|
|
155
|
+
}
|
|
156
|
+
/** Ergebnis der PIN-Anmeldung. */
|
|
157
|
+
export interface RegisterUserSession {
|
|
158
|
+
/**
|
|
159
|
+
* Firebase-Custom-Token. Damit meldet der Verbraucher sich bei Firebase an
|
|
160
|
+
* und bekommt das ID-Token, das `registerUserAuth` braucht; dieses Paket
|
|
161
|
+
* kennt Firebase nicht.
|
|
162
|
+
*/
|
|
163
|
+
customToken: string;
|
|
164
|
+
/** Laufende Sitzung — Kopfzeile `register-session` jedes weiteren Aufrufs. */
|
|
165
|
+
sessionId: string;
|
|
166
|
+
/**
|
|
167
|
+
* Ablauf der Sitzung in Millisekunden seit 1970 (das Backend rechnet hier mit
|
|
168
|
+
* `Date.now()`, nicht mit Wiener Wanduhrzeit). Die Sitzung lebt 90 Sekunden
|
|
169
|
+
* und will alle 30 Sekunden erneuert werden.
|
|
170
|
+
*/
|
|
171
|
+
expiresAt: number;
|
|
172
|
+
user: RegisterUser;
|
|
173
|
+
}
|
|
174
|
+
export interface ListRegisterUsersForDeviceOptions extends RegisterDeviceConnection, RegisterDeviceCredentials {
|
|
175
|
+
}
|
|
176
|
+
export interface RegisterUserLoginOptions extends RegisterDeviceConnection, RegisterDeviceCredentials, RegisterGeraeteAngaben {
|
|
177
|
+
/** Kassen-Benutzer aus [listRegisterUsersForDevice]. */
|
|
178
|
+
userId: string;
|
|
179
|
+
/**
|
|
180
|
+
* PIN dieses Benutzers. Das Format prueft dieses Paket **nicht**: eine zu
|
|
181
|
+
* strenge Pruefung im Client sperrte Benutzer aus, deren PIN das Panel anders
|
|
182
|
+
* gesetzt hat.
|
|
183
|
+
*/
|
|
184
|
+
pin: string;
|
|
185
|
+
/** Kasse, an der die Sitzung eroeffnet wird. */
|
|
186
|
+
cashregisterId: string;
|
|
187
|
+
/**
|
|
188
|
+
* Eine belegte Kasse uebernehmen. Nur mit dem Recht `takeover` (Kassen-Chef);
|
|
189
|
+
* die aelteste laufende Sitzung wird dabei verdraengt. Ohne das Recht bleibt
|
|
190
|
+
* es bei der Abweisung "Kasse wird gerade auf … verwendet".
|
|
191
|
+
*/
|
|
192
|
+
takeover?: boolean;
|
|
193
|
+
}
|
|
194
|
+
export interface RegisterPinLoginOptions extends RegisterDeviceConnection, RegisterDeviceCredentials, RegisterGeraeteAngaben {
|
|
195
|
+
/**
|
|
196
|
+
* Die PIN allein — sie identifiziert UND authentifiziert (Geraete-Modus
|
|
197
|
+
* `pin`; das Backend haelt PINs je Betrieb eindeutig). Das Format prueft
|
|
198
|
+
* dieses Paket **nicht** — dieselbe Zurueckhaltung wie bei
|
|
199
|
+
* [RegisterUserLoginOptions.pin].
|
|
200
|
+
*/
|
|
201
|
+
pin: string;
|
|
202
|
+
/** Kasse, an der die Sitzung eroeffnet wird. */
|
|
203
|
+
cashregisterId: string;
|
|
204
|
+
/** Wie [RegisterUserLoginOptions.takeover]. */
|
|
205
|
+
takeover?: boolean;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Geraet koppeln: der Kopplungs-Code wird gegen den dauerhaften Ausweis dieses
|
|
209
|
+
* Geraets getauscht. **Ohne Anmeldung** — der Code ist der Nachweis.
|
|
210
|
+
*
|
|
211
|
+
* Er wird dabei verbraucht, auch wenn der Aufrufer das Ergebnis verliert: eine
|
|
212
|
+
* unvollstaendige Antwort ist deshalb ein Fehler und kein halbes Geraet (siehe
|
|
213
|
+
* [PairedRegisterDevice]).
|
|
214
|
+
*/
|
|
215
|
+
export declare function pairRegisterDevice(options: PairRegisterDeviceOptions): Promise<PairedRegisterDevice>;
|
|
216
|
+
/**
|
|
217
|
+
* Kassen-Benutzer dieses Betriebs auflisten — die Auswahl des
|
|
218
|
+
* Anmeldebildschirms. **Ohne Anmeldung**; der Ausweis des Geraets ist der
|
|
219
|
+
* Nachweis.
|
|
220
|
+
*
|
|
221
|
+
* Die Antwort traegt ausschliesslich Kennung, Name und Art: keine Rechte, keine
|
|
222
|
+
* Kassen, keine Hashes. Gesperrte Benutzer fehlen bereits in der Antwort.
|
|
223
|
+
*/
|
|
224
|
+
/**
|
|
225
|
+
* „Geraet entkoppeln“ an der Kasse selbst: das Geraet weist sich mit seinem
|
|
226
|
+
* Geheimnis aus und sperrt sich im Backend — damit sieht das Panel den
|
|
227
|
+
* Widerruf und keine Sitzung laeuft nach. Idempotent: ein schon gesperrtes
|
|
228
|
+
* Geraet meldet Erfolg. Danach das Geraet lokal vergessen.
|
|
229
|
+
*/
|
|
230
|
+
export declare function unpairRegisterDevice(options: ListRegisterUsersForDeviceOptions): Promise<void>;
|
|
231
|
+
export declare function listRegisterUsersForDevice(options: ListRegisterUsersForDeviceOptions): Promise<RegisterDeviceUsers>;
|
|
232
|
+
/**
|
|
233
|
+
* Kassen-Benutzer per PIN anmelden. **Ohne Anmeldung** — dieser Aufruf
|
|
234
|
+
* erzeugt sie: das Custom Token der Antwort wird zum ID-Token, die `sessionId`
|
|
235
|
+
* zur Kopfzeile `register-session`. Beides zusammen ergibt `registerUserAuth`.
|
|
236
|
+
*
|
|
237
|
+
* Das Backend prueft in dieser Reihenfolge: Geraet, Benutzer, Sperre, PIN,
|
|
238
|
+
* Kassenzuweisung, Kopplungsbindung, Lizenzplatz. Fehlversuche zaehlen und
|
|
239
|
+
* sperren gestaffelt (ab dem fuenften 30 Sekunden, ab dem neunten 15 Minuten).
|
|
240
|
+
*/
|
|
241
|
+
export declare function registerUserLogin(options: RegisterUserLoginOptions): Promise<RegisterUserSession>;
|
|
242
|
+
/**
|
|
243
|
+
* Kassen-Benutzer allein mit der PIN anmelden (Geraete-Modus `pin`). **Ohne
|
|
244
|
+
* Anmeldung** — wie [registerUserLogin], nur ohne Benutzerauswahl: das Backend
|
|
245
|
+
* ermittelt den Benutzer ueber die betriebsweit eindeutige PIN. Fehlversuche
|
|
246
|
+
* zaehlen und sperren dort am **Geraet**, nicht an einem Benutzer.
|
|
247
|
+
*/
|
|
248
|
+
export declare function registerPinLogin(options: RegisterPinLoginOptions): Promise<RegisterUserSession>;
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { KasseneckValidationError } from '../client/errors.js';
|
|
2
|
+
import { createTransport } from '../client/transport.js';
|
|
3
|
+
import { fromReceiptCompanyPayload } from '../models/receipt-company.js';
|
|
4
|
+
import { KASSE_BETRIEB_STANDARD, KASSE_GERAET_STANDARD, mergeKasseSettings, } from '../kasse/settings.js';
|
|
5
|
+
/**
|
|
6
|
+
* Die drei Aufrufe, die **ohne jede Identitaet** laufen: Kopplung eines
|
|
7
|
+
* Geraets, Benutzerliste dieses Geraets, PIN-Anmeldung. Sie sind der Weg, auf
|
|
8
|
+
* dem eine Identitaet ueberhaupt erst entsteht — vor ihnen gibt es weder
|
|
9
|
+
* ID-Token noch Sitzung noch `api_key`.
|
|
10
|
+
*
|
|
11
|
+
* **Warum sie keine Anmeldung und keinen Transport entgegennehmen.** Alle
|
|
12
|
+
* uebrigen Endpunkt-Aufrufe dieses Pakets bekommen einen fertigen
|
|
13
|
+
* [KasseneckTransport] als ersten Parameter. Hier ginge das nur mit einer
|
|
14
|
+
* anmeldungsfreien Anmeldung — und die muesste dann exportiert sein. Genau das
|
|
15
|
+
* waere ein Schlupfloch: mit ihr liesse sich `createTransport` bzw.
|
|
16
|
+
* `createKasseneckApi` bauen und damit **jeder** Aufruf des Pakets ohne
|
|
17
|
+
* Anmeldung absetzen, auch `createReceipt`. Das Backend wiese das ab, aber ein
|
|
18
|
+
* Paket, das den Weg anbietet, sagt damit, dass es ihn gibt.
|
|
19
|
+
*
|
|
20
|
+
* Deshalb nehmen diese drei nur die **Verbindungsangaben** (Basis-URL,
|
|
21
|
+
* Zeitlimit, `fetch`) entgegen und bauen ihren Transport selbst — mit einer
|
|
22
|
+
* Anmeldung, die diese Datei nicht verlaesst. Damit gibt es im ganzen Paket
|
|
23
|
+
* keinen Weg, einen anmeldungsfreien Transport in die Hand zu bekommen.
|
|
24
|
+
*
|
|
25
|
+
* **Geheimnisse in der Nutzlast.** Diese drei Aufrufe fuehren Kopplungs-Code,
|
|
26
|
+
* Geraetegeheimnis und PIN — nicht in Kopfzeilen, sondern im Rumpf. Der
|
|
27
|
+
* Transport schuetzt seine Fehler von sich aus nur gegen die Werte, die er als
|
|
28
|
+
* Kopfzeilen gesendet hat (siehe client/errors.ts, `causeDigest`); hier ist
|
|
29
|
+
* diese Liste leer. Die Aufrufe nennen ihm ihre Geheimnisse deshalb
|
|
30
|
+
* ausdruecklich, sonst kaeme ein bezeichner-foermiges Geraetegeheimnis ueber
|
|
31
|
+
* die verdichtete Ursache eines Netzfehlers doch noch ins Protokoll.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Anmeldung, die keine ist: weder Kopfzeilen noch Zusatzparameter.
|
|
35
|
+
*
|
|
36
|
+
* **Nicht exportiert und niemals exportieren** — der Grund steht im
|
|
37
|
+
* Modulkommentar. Pro Aufruf ein frisches Objekt, wie die echten Anmeldungen
|
|
38
|
+
* es auch halten.
|
|
39
|
+
*/
|
|
40
|
+
const ohneAnmeldung = () => ({ headers: {}, params: {} });
|
|
41
|
+
/** Reichweite lesen, mit der Migration des Backends (register-auth.js). */
|
|
42
|
+
export function cancelScopeOf(perms) {
|
|
43
|
+
if (!perms)
|
|
44
|
+
return 'none';
|
|
45
|
+
if (perms.cancelScope !== undefined)
|
|
46
|
+
return ['none', 'own', 'all'].includes(perms.cancelScope) ? perms.cancelScope : 'none';
|
|
47
|
+
return perms.cancel === true ? 'all' : 'none';
|
|
48
|
+
}
|
|
49
|
+
export function receiptsScopeOf(perms) {
|
|
50
|
+
if (!perms)
|
|
51
|
+
return 'none';
|
|
52
|
+
if (perms.receiptsScope === undefined)
|
|
53
|
+
return 'all';
|
|
54
|
+
return ['none', 'own', 'all'].includes(perms.receiptsScope) ? perms.receiptsScope : 'none';
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Geraet koppeln: der Kopplungs-Code wird gegen den dauerhaften Ausweis dieses
|
|
58
|
+
* Geraets getauscht. **Ohne Anmeldung** — der Code ist der Nachweis.
|
|
59
|
+
*
|
|
60
|
+
* Er wird dabei verbraucht, auch wenn der Aufrufer das Ergebnis verliert: eine
|
|
61
|
+
* unvollstaendige Antwort ist deshalb ein Fehler und kein halbes Geraet (siehe
|
|
62
|
+
* [PairedRegisterDevice]).
|
|
63
|
+
*/
|
|
64
|
+
export async function pairRegisterDevice(options) {
|
|
65
|
+
const { code, label, client, geo, ...verbindung } = options;
|
|
66
|
+
pflicht('pairRegisterDevice', 'code', code);
|
|
67
|
+
// Der Code ist das Geheimnis dieses Aufrufs — siehe Modulkommentar.
|
|
68
|
+
const daten = await transportFuer(verbindung)('pairRegisterDevice', { code, label, client, geo: geo ?? undefined }, undefined, [code]);
|
|
69
|
+
return {
|
|
70
|
+
deviceId: pflichtfeld('pairRegisterDevice', daten, 'deviceId'),
|
|
71
|
+
deviceSecret: pflichtfeld('pairRegisterDevice', daten, 'deviceSecret'),
|
|
72
|
+
ownerUid: pflichtfeld('pairRegisterDevice', daten, 'ownerUid'),
|
|
73
|
+
cashregisterId: pflichtfeld('pairRegisterDevice', daten, 'cashregisterId'),
|
|
74
|
+
companyName: text(daten?.['betrieb']),
|
|
75
|
+
cashregisterLabel: text(daten?.['kasse']),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Kassen-Benutzer dieses Betriebs auflisten — die Auswahl des
|
|
80
|
+
* Anmeldebildschirms. **Ohne Anmeldung**; der Ausweis des Geraets ist der
|
|
81
|
+
* Nachweis.
|
|
82
|
+
*
|
|
83
|
+
* Die Antwort traegt ausschliesslich Kennung, Name und Art: keine Rechte, keine
|
|
84
|
+
* Kassen, keine Hashes. Gesperrte Benutzer fehlen bereits in der Antwort.
|
|
85
|
+
*/
|
|
86
|
+
/**
|
|
87
|
+
* „Geraet entkoppeln“ an der Kasse selbst: das Geraet weist sich mit seinem
|
|
88
|
+
* Geheimnis aus und sperrt sich im Backend — damit sieht das Panel den
|
|
89
|
+
* Widerruf und keine Sitzung laeuft nach. Idempotent: ein schon gesperrtes
|
|
90
|
+
* Geraet meldet Erfolg. Danach das Geraet lokal vergessen.
|
|
91
|
+
*/
|
|
92
|
+
export async function unpairRegisterDevice(options) {
|
|
93
|
+
const { ownerUid, deviceId, deviceSecret, ...verbindung } = options;
|
|
94
|
+
const name = 'unpairRegisterDevice';
|
|
95
|
+
pflicht(name, 'ownerUid', ownerUid);
|
|
96
|
+
pflicht(name, 'deviceId', deviceId);
|
|
97
|
+
pflicht(name, 'deviceSecret', deviceSecret);
|
|
98
|
+
await transportFuer(verbindung)(name, { ownerUid, deviceId, deviceSecret }, undefined, [deviceSecret]);
|
|
99
|
+
}
|
|
100
|
+
export async function listRegisterUsersForDevice(options) {
|
|
101
|
+
const { ownerUid, deviceId, deviceSecret, ...verbindung } = options;
|
|
102
|
+
const name = 'listRegisterUsersForDevice';
|
|
103
|
+
pflicht(name, 'ownerUid', ownerUid);
|
|
104
|
+
pflicht(name, 'deviceId', deviceId);
|
|
105
|
+
pflicht(name, 'deviceSecret', deviceSecret);
|
|
106
|
+
const daten = await transportFuer(verbindung)(name, { ownerUid, deviceId, deviceSecret }, undefined, [deviceSecret]);
|
|
107
|
+
const liste = daten?.users;
|
|
108
|
+
if (!Array.isArray(liste)) {
|
|
109
|
+
throw antwortfehler(name, 'Antwort enthaelt keine Benutzerliste (data.users fehlt)');
|
|
110
|
+
}
|
|
111
|
+
const users = liste.map((eintrag) => {
|
|
112
|
+
const roh = (typeof eintrag === 'object' && eintrag !== null ? eintrag : {});
|
|
113
|
+
return {
|
|
114
|
+
// Ein Eintrag ohne Kennung ist nicht anmeldbar — ihn anzuzeigen hiesse,
|
|
115
|
+
// dem Kassier eine Schaltflaeche zu geben, die nichts tun kann.
|
|
116
|
+
id: pflichtfeld(name, roh, 'id'),
|
|
117
|
+
name: text(roh['name']),
|
|
118
|
+
kind: typeof roh['kind'] === 'string' && roh['kind'] ? roh['kind'] : 'person',
|
|
119
|
+
altbestand: roh['altbestand'] === true,
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
const settingsRoh = (daten?.settings ?? {});
|
|
123
|
+
const settings = {
|
|
124
|
+
betrieb: mergeKasseSettings(KASSE_BETRIEB_STANDARD, (settingsRoh.betrieb ?? null)),
|
|
125
|
+
geraet: mergeKasseSettings(KASSE_GERAET_STANDARD, (settingsRoh.geraet ?? null)),
|
|
126
|
+
};
|
|
127
|
+
const bd = daten?.betriebsdaten;
|
|
128
|
+
const betriebsdaten = bd && typeof bd === 'object' ? fromReceiptCompanyPayload(bd) : null;
|
|
129
|
+
return { users, policy: regel(daten?.policy), loginMode: daten?.loginMode === 'pin' ? 'pin' : 'auswahl', settings, betriebsdaten, standortsperre: daten?.standortsperre === true };
|
|
130
|
+
}
|
|
131
|
+
/** Die Regel aus der Antwort — oder `null`, wenn keine brauchbare kommt. */
|
|
132
|
+
function regel(wert) {
|
|
133
|
+
if (typeof wert !== 'object' || wert === null || Array.isArray(wert))
|
|
134
|
+
return null;
|
|
135
|
+
const roh = wert;
|
|
136
|
+
const stellen = roh['stellen'];
|
|
137
|
+
const zeichen = roh['zeichen'];
|
|
138
|
+
if (typeof stellen !== 'number' || !Number.isInteger(stellen) || stellen < 1)
|
|
139
|
+
return null;
|
|
140
|
+
if (typeof zeichen !== 'string' || zeichen === '')
|
|
141
|
+
return null;
|
|
142
|
+
return { stellen, zeichen: zeichen };
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Kassen-Benutzer per PIN anmelden. **Ohne Anmeldung** — dieser Aufruf
|
|
146
|
+
* erzeugt sie: das Custom Token der Antwort wird zum ID-Token, die `sessionId`
|
|
147
|
+
* zur Kopfzeile `register-session`. Beides zusammen ergibt `registerUserAuth`.
|
|
148
|
+
*
|
|
149
|
+
* Das Backend prueft in dieser Reihenfolge: Geraet, Benutzer, Sperre, PIN,
|
|
150
|
+
* Kassenzuweisung, Kopplungsbindung, Lizenzplatz. Fehlversuche zaehlen und
|
|
151
|
+
* sperren gestaffelt (ab dem fuenften 30 Sekunden, ab dem neunten 15 Minuten).
|
|
152
|
+
*/
|
|
153
|
+
export async function registerUserLogin(options) {
|
|
154
|
+
const { ownerUid, deviceId, deviceSecret, userId, pin, cashregisterId, takeover, client, geo, ...verbindung } = options;
|
|
155
|
+
const name = 'registerUserLogin';
|
|
156
|
+
pflicht(name, 'ownerUid', ownerUid);
|
|
157
|
+
pflicht(name, 'deviceId', deviceId);
|
|
158
|
+
pflicht(name, 'deviceSecret', deviceSecret);
|
|
159
|
+
pflicht(name, 'userId', userId);
|
|
160
|
+
pflicht(name, 'pin', pin);
|
|
161
|
+
pflicht(name, 'cashregisterId', cashregisterId);
|
|
162
|
+
const daten = await transportFuer(verbindung)(name, {
|
|
163
|
+
ownerUid,
|
|
164
|
+
deviceId,
|
|
165
|
+
deviceSecret,
|
|
166
|
+
userId,
|
|
167
|
+
pin,
|
|
168
|
+
cashregisterId,
|
|
169
|
+
// Nur die ausdrueckliche Uebernahme geht mit: das Backend prueft auf
|
|
170
|
+
// `=== true`, und ein mitgesendetes `false` waere nur Rauschen.
|
|
171
|
+
takeover: takeover === true ? true : undefined,
|
|
172
|
+
client, geo: geo ?? undefined,
|
|
173
|
+
}, undefined, [pin, deviceSecret]);
|
|
174
|
+
return sitzungAusAntwort(name, daten);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Kassen-Benutzer allein mit der PIN anmelden (Geraete-Modus `pin`). **Ohne
|
|
178
|
+
* Anmeldung** — wie [registerUserLogin], nur ohne Benutzerauswahl: das Backend
|
|
179
|
+
* ermittelt den Benutzer ueber die betriebsweit eindeutige PIN. Fehlversuche
|
|
180
|
+
* zaehlen und sperren dort am **Geraet**, nicht an einem Benutzer.
|
|
181
|
+
*/
|
|
182
|
+
export async function registerPinLogin(options) {
|
|
183
|
+
const { ownerUid, deviceId, deviceSecret, pin, cashregisterId, takeover, client, geo, ...verbindung } = options;
|
|
184
|
+
const name = 'registerPinLogin';
|
|
185
|
+
pflicht(name, 'ownerUid', ownerUid);
|
|
186
|
+
pflicht(name, 'deviceId', deviceId);
|
|
187
|
+
pflicht(name, 'deviceSecret', deviceSecret);
|
|
188
|
+
pflicht(name, 'pin', pin);
|
|
189
|
+
pflicht(name, 'cashregisterId', cashregisterId);
|
|
190
|
+
const daten = await transportFuer(verbindung)(name, {
|
|
191
|
+
ownerUid,
|
|
192
|
+
deviceId,
|
|
193
|
+
deviceSecret,
|
|
194
|
+
pin,
|
|
195
|
+
cashregisterId,
|
|
196
|
+
// Nur die ausdrueckliche Uebernahme geht mit — wie bei registerUserLogin.
|
|
197
|
+
takeover: takeover === true ? true : undefined,
|
|
198
|
+
client, geo: geo ?? undefined,
|
|
199
|
+
}, undefined, [pin, deviceSecret]);
|
|
200
|
+
return sitzungAusAntwort(name, daten);
|
|
201
|
+
}
|
|
202
|
+
/** Die Sitzungsantwort beider Anmeldewege — ein Vertrag, eine Lesart. */
|
|
203
|
+
function sitzungAusAntwort(name, daten) {
|
|
204
|
+
const roherBenutzer = daten?.['user'];
|
|
205
|
+
if (typeof roherBenutzer !== 'object' || roherBenutzer === null || Array.isArray(roherBenutzer)) {
|
|
206
|
+
throw antwortfehler(name, 'Antwort enthaelt keinen Benutzer (data.user fehlt)');
|
|
207
|
+
}
|
|
208
|
+
const benutzer = roherBenutzer;
|
|
209
|
+
const expiresAt = daten?.['expiresAt'];
|
|
210
|
+
if (typeof expiresAt !== 'number' || !Number.isFinite(expiresAt)) {
|
|
211
|
+
throw antwortfehler(name, 'Antwort enthaelt keinen Ablaufzeitpunkt (data.expiresAt fehlt)');
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
customToken: pflichtfeld(name, daten, 'customToken'),
|
|
215
|
+
sessionId: pflichtfeld(name, daten, 'sessionId'),
|
|
216
|
+
expiresAt,
|
|
217
|
+
user: {
|
|
218
|
+
id: pflichtfeld(name, benutzer, 'id'),
|
|
219
|
+
name: text(benutzer['name']),
|
|
220
|
+
perms: rechte(benutzer['perms']),
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/** Transport ohne Anmeldung; `auth` steht zuletzt und ist damit nicht zu ueberschreiben. */
|
|
225
|
+
function transportFuer(verbindung) {
|
|
226
|
+
return createTransport({ ...verbindung, auth: ohneAnmeldung });
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Pflichtangabe des Aufrufers. Die Meldung nennt das **Feld**, nie seinen Wert
|
|
230
|
+
* — das Feld heisst `pin`, `deviceSecret` oder `code`.
|
|
231
|
+
*/
|
|
232
|
+
function pflicht(functionName, feld, wert) {
|
|
233
|
+
if (typeof wert !== 'string' || wert.trim() === '') {
|
|
234
|
+
throw new KasseneckValidationError(functionName, `${feld} fehlt`, 'request');
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Pflichtfeld der Antwort. Auch hier wandert **nichts aus der Antwort** in die
|
|
239
|
+
* Meldung; genannt wird nur, welches Feld fehlt.
|
|
240
|
+
*/
|
|
241
|
+
function pflichtfeld(functionName, daten, feld) {
|
|
242
|
+
const wert = daten?.[feld];
|
|
243
|
+
if (typeof wert !== 'string' || wert === '') {
|
|
244
|
+
throw antwortfehler(functionName, `Antwort enthaelt kein Feld "${feld}"`);
|
|
245
|
+
}
|
|
246
|
+
return wert;
|
|
247
|
+
}
|
|
248
|
+
/** Rechte lesen: nur Wahrheitswerte, alles Fehlende gilt als nicht erteilt. */
|
|
249
|
+
function rechte(wert) {
|
|
250
|
+
const roh = (typeof wert === 'object' && wert !== null && !Array.isArray(wert) ? wert : {});
|
|
251
|
+
const gelesen = {};
|
|
252
|
+
for (const [name, inhalt] of Object.entries(roh)) {
|
|
253
|
+
gelesen[name] = inhalt === true;
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
sell: false,
|
|
257
|
+
cancel: false,
|
|
258
|
+
articles: false,
|
|
259
|
+
layout: false,
|
|
260
|
+
reports: false,
|
|
261
|
+
takeover: false,
|
|
262
|
+
...gelesen,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
/** Leere Zeichenkette statt `undefined` — Anzeigefelder duerfen leer sein. */
|
|
266
|
+
const text = (wert) => (typeof wert === 'string' ? wert : '');
|
|
267
|
+
/** Die Antwort meldete Erfolg, trug aber nicht, was der Aufruf zusagt. */
|
|
268
|
+
function antwortfehler(functionName, grund) {
|
|
269
|
+
return new KasseneckValidationError(functionName, grund, 'response');
|
|
270
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { KasseneckTransport } from '../client/transport.js';
|
|
2
|
+
/**
|
|
3
|
+
* Die beiden Aufrufe der **laufenden** Kassen-Sitzung. Anders als die drei in
|
|
4
|
+
* pairing.ts haben sie eine Identitaet: sie laufen ueber `registerUserAuth`
|
|
5
|
+
* (ID-Token als Bearer, Sitzung als Kopfzeile `register-session`) und nehmen
|
|
6
|
+
* darum einen fertigen [KasseneckTransport] entgegen wie jeder andere
|
|
7
|
+
* Endpunkt-Aufruf dieses Pakets.
|
|
8
|
+
*
|
|
9
|
+
* Beide fuehren **keinen einzigen Parameter**: welche Sitzung gemeint ist,
|
|
10
|
+
* steht im Token und in der Kopfzeile. Der Parameter `cashregisterId`, den man
|
|
11
|
+
* im Rumpf sieht, kommt aus der Anmeldung.
|
|
12
|
+
*
|
|
13
|
+
* Das Backend setzt fuer beide `allowRegisterUser`; mit `apiKeyAuth` sind sie
|
|
14
|
+
* nicht erreichbar (dieses Paket bildet das nicht nach — wer darf, entscheidet
|
|
15
|
+
* das Backend).
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Sitzung verlaengern und den neuen Ablaufzeitpunkt liefern (Millisekunden
|
|
19
|
+
* seit 1970).
|
|
20
|
+
*
|
|
21
|
+
* Die Sitzung lebt 90 Sekunden; die Browser-Kasse erneuert alle 30. Ist sie
|
|
22
|
+
* bereits beendet oder uebernommen, antwortet das Backend fachlich ("Sitzung
|
|
23
|
+
* beendet — bitte neu anmelden.") — dann hilft nur eine neue Anmeldung ueber
|
|
24
|
+
* `registerUserLogin`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function renewRegisterSession(rufen: KasseneckTransport): Promise<number>;
|
|
27
|
+
/**
|
|
28
|
+
* Sitzung beenden und den Lizenzplatz sofort freigeben — der regulaere Weg des
|
|
29
|
+
* Abmeldens.
|
|
30
|
+
*
|
|
31
|
+
* Das Backend antwortet mit `{ok:true}`; dieser Aufruf prueft das Feld
|
|
32
|
+
* **nicht**: dass der Vorgang gelang, sagt bereits die Erfolgshuelle, die der
|
|
33
|
+
* Transport auswertet. Eine zweite Pruefung derselben Aussage braeche nur an
|
|
34
|
+
* einer harmlosen Vertragsaenderung — ausgerechnet beim Abmelden, dem Aufruf,
|
|
35
|
+
* der auch dann durchgehen soll, wenn sonst nichts mehr geht.
|
|
36
|
+
*/
|
|
37
|
+
export declare function endRegisterSession(rufen: KasseneckTransport): Promise<void>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { KasseneckValidationError } from '../client/errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Die beiden Aufrufe der **laufenden** Kassen-Sitzung. Anders als die drei in
|
|
4
|
+
* pairing.ts haben sie eine Identitaet: sie laufen ueber `registerUserAuth`
|
|
5
|
+
* (ID-Token als Bearer, Sitzung als Kopfzeile `register-session`) und nehmen
|
|
6
|
+
* darum einen fertigen [KasseneckTransport] entgegen wie jeder andere
|
|
7
|
+
* Endpunkt-Aufruf dieses Pakets.
|
|
8
|
+
*
|
|
9
|
+
* Beide fuehren **keinen einzigen Parameter**: welche Sitzung gemeint ist,
|
|
10
|
+
* steht im Token und in der Kopfzeile. Der Parameter `cashregisterId`, den man
|
|
11
|
+
* im Rumpf sieht, kommt aus der Anmeldung.
|
|
12
|
+
*
|
|
13
|
+
* Das Backend setzt fuer beide `allowRegisterUser`; mit `apiKeyAuth` sind sie
|
|
14
|
+
* nicht erreichbar (dieses Paket bildet das nicht nach — wer darf, entscheidet
|
|
15
|
+
* das Backend).
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Sitzung verlaengern und den neuen Ablaufzeitpunkt liefern (Millisekunden
|
|
19
|
+
* seit 1970).
|
|
20
|
+
*
|
|
21
|
+
* Die Sitzung lebt 90 Sekunden; die Browser-Kasse erneuert alle 30. Ist sie
|
|
22
|
+
* bereits beendet oder uebernommen, antwortet das Backend fachlich ("Sitzung
|
|
23
|
+
* beendet — bitte neu anmelden.") — dann hilft nur eine neue Anmeldung ueber
|
|
24
|
+
* `registerUserLogin`.
|
|
25
|
+
*/
|
|
26
|
+
export async function renewRegisterSession(rufen) {
|
|
27
|
+
const daten = await rufen('renewRegisterSession');
|
|
28
|
+
const expiresAt = daten?.expiresAt;
|
|
29
|
+
if (typeof expiresAt !== 'number' || !Number.isFinite(expiresAt)) {
|
|
30
|
+
// Ohne brauchbaren Ablaufzeitpunkt weiss die Kasse nicht, wann sie das
|
|
31
|
+
// naechste Mal erneuern muss — das ist ein Antwortfehler und kein Erfolg.
|
|
32
|
+
throw new KasseneckValidationError('renewRegisterSession', 'Antwort enthaelt keinen Ablaufzeitpunkt (data.expiresAt fehlt)', 'response');
|
|
33
|
+
}
|
|
34
|
+
return expiresAt;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Sitzung beenden und den Lizenzplatz sofort freigeben — der regulaere Weg des
|
|
38
|
+
* Abmeldens.
|
|
39
|
+
*
|
|
40
|
+
* Das Backend antwortet mit `{ok:true}`; dieser Aufruf prueft das Feld
|
|
41
|
+
* **nicht**: dass der Vorgang gelang, sagt bereits die Erfolgshuelle, die der
|
|
42
|
+
* Transport auswertet. Eine zweite Pruefung derselben Aussage braeche nur an
|
|
43
|
+
* einer harmlosen Vertragsaenderung — ausgerechnet beim Abmelden, dem Aufruf,
|
|
44
|
+
* der auch dann durchgehen soll, wenn sonst nichts mehr geht.
|
|
45
|
+
*/
|
|
46
|
+
export async function endRegisterSession(rufen) {
|
|
47
|
+
await rufen('endRegisterSession');
|
|
48
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-Zeitstempel parsen: ohne Offset = Wiener Wanduhrzeit, mit
|
|
3
|
+
* Offset/`Z` = bereits ein echter Zeitpunkt. Ergebnis ist immer ein echter
|
|
4
|
+
* Zeitpunkt (JS-`Date`, intern UTC-Millisekunden seit Epoch).
|
|
5
|
+
*/
|
|
6
|
+
export declare function parseServerTimeStamp(raw: string): Date;
|
|
7
|
+
/** Wiener Wanduhrzeit: die Ziffern, die eine Uhr in Wien anzeigt. `month` ist 1-12. */
|
|
8
|
+
export interface ViennaWallClock {
|
|
9
|
+
year: number;
|
|
10
|
+
month: number;
|
|
11
|
+
day: number;
|
|
12
|
+
hour: number;
|
|
13
|
+
minute: number;
|
|
14
|
+
second: number;
|
|
15
|
+
millisecond: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Echter Zeitpunkt -> Wiener Wanduhrzeit (Gegenstueck zu
|
|
19
|
+
* [parseServerTimeStamp]). Der Versatz kommt aus derselben Sommerzeitregel wie
|
|
20
|
+
* die Hinrichtung; hier ist er direkt anwendbar, weil der Zeitpunkt schon
|
|
21
|
+
* feststeht.
|
|
22
|
+
*/
|
|
23
|
+
export declare function toViennaWallClock(zeitpunkt: Date): ViennaWallClock;
|