@kreiseck/kasseneck-api 0.13.2 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +98 -0
- package/README.md +96 -5
- package/dist/cjs/client/aufrufe.d.ts +1 -1
- package/dist/cjs/client/aufrufe.js +11 -0
- package/dist/cjs/client/receipts.d.ts +7 -0
- package/dist/cjs/client/receipts.js +1 -0
- package/dist/cjs/kasse/drucker.d.ts +5 -0
- package/dist/cjs/kasse/drucker.js +9 -0
- package/dist/cjs/kasse/settings.js +5 -2
- package/dist/cjs/printing/escpos.d.ts +38 -4
- package/dist/cjs/printing/escpos.js +87 -15
- package/dist/cjs/printing/index.d.ts +2 -2
- package/dist/cjs/printing/index.js +5 -1
- package/dist/cjs/printing/qr-groesse.d.ts +26 -21
- package/dist/cjs/printing/qr-groesse.js +22 -8
- package/dist/cjs/react/index.d.ts +53 -0
- package/dist/cjs/react/index.js +81 -0
- package/dist/cjs/receipt/bild.d.ts +14 -0
- package/dist/cjs/receipt/bild.js +65 -0
- package/dist/cjs/receipt/blatt.d.ts +107 -0
- package/dist/cjs/receipt/blatt.js +137 -0
- package/dist/cjs/receipt/epos.d.ts +19 -8
- package/dist/cjs/receipt/epos.js +39 -20
- package/dist/cjs/receipt/grid.d.ts +1 -1
- package/dist/cjs/receipt/grid.js +9 -1
- package/dist/cjs/receipt/index.d.ts +4 -2
- package/dist/cjs/receipt/index.js +17 -1
- package/dist/cjs/receipt/layout-escpos.d.ts +31 -3
- package/dist/cjs/receipt/layout-escpos.js +58 -18
- package/dist/cjs/rechnung/api.d.ts +43 -0
- package/dist/cjs/rechnung/api.js +35 -0
- package/dist/cjs/rechnung/auth.d.ts +21 -0
- package/dist/cjs/rechnung/auth.js +36 -0
- package/dist/cjs/rechnung/endpunkte.d.ts +48 -0
- package/dist/cjs/rechnung/endpunkte.js +129 -0
- package/dist/cjs/rechnung/fehler.d.ts +21 -0
- package/dist/cjs/rechnung/fehler.js +44 -0
- package/dist/cjs/rechnung/index.d.ts +18 -0
- package/dist/cjs/rechnung/index.js +52 -0
- package/dist/cjs/rechnung/typen.d.ts +224 -0
- package/dist/cjs/rechnung/typen.js +9 -0
- package/dist/cjs/rechnung/vertrag.d.ts +98 -0
- package/dist/cjs/rechnung/vertrag.js +191 -0
- package/dist/esm/client/aufrufe.d.ts +1 -1
- package/dist/esm/client/aufrufe.js +11 -0
- package/dist/esm/client/receipts.d.ts +7 -0
- package/dist/esm/client/receipts.js +1 -0
- package/dist/esm/kasse/drucker.d.ts +5 -0
- package/dist/esm/kasse/drucker.js +9 -0
- package/dist/esm/kasse/settings.js +5 -2
- package/dist/esm/printing/escpos.d.ts +38 -4
- package/dist/esm/printing/escpos.js +84 -15
- package/dist/esm/printing/index.d.ts +2 -2
- package/dist/esm/printing/index.js +2 -2
- package/dist/esm/printing/qr-groesse.d.ts +26 -21
- package/dist/esm/printing/qr-groesse.js +21 -8
- package/dist/esm/react/index.d.ts +53 -0
- package/dist/esm/react/index.js +80 -1
- package/dist/esm/receipt/bild.d.ts +14 -0
- package/dist/esm/receipt/bild.js +62 -0
- package/dist/esm/receipt/blatt.d.ts +107 -0
- package/dist/esm/receipt/blatt.js +128 -0
- package/dist/esm/receipt/epos.d.ts +19 -8
- package/dist/esm/receipt/epos.js +40 -22
- package/dist/esm/receipt/grid.d.ts +1 -1
- package/dist/esm/receipt/grid.js +9 -1
- package/dist/esm/receipt/index.d.ts +4 -2
- package/dist/esm/receipt/index.js +4 -2
- package/dist/esm/receipt/layout-escpos.d.ts +31 -3
- package/dist/esm/receipt/layout-escpos.js +58 -20
- package/dist/esm/rechnung/api.d.ts +43 -0
- package/dist/esm/rechnung/api.js +32 -0
- package/dist/esm/rechnung/auth.d.ts +21 -0
- package/dist/esm/rechnung/auth.js +33 -0
- package/dist/esm/rechnung/endpunkte.d.ts +48 -0
- package/dist/esm/rechnung/endpunkte.js +116 -0
- package/dist/esm/rechnung/fehler.d.ts +21 -0
- package/dist/esm/rechnung/fehler.js +39 -0
- package/dist/esm/rechnung/index.d.ts +18 -0
- package/dist/esm/rechnung/index.js +17 -0
- package/dist/esm/rechnung/typen.d.ts +224 -0
- package/dist/esm/rechnung/typen.js +8 -0
- package/dist/esm/rechnung/vertrag.d.ts +98 -0
- package/dist/esm/rechnung/vertrag.js +188 -0
- package/fixtures/erwartet/karte-eigener.blatt32.json +159 -0
- package/fixtures/erwartet/karte-eigener.blatt48.json +159 -0
- package/fixtures/erwartet/karte-gptom-ios.blatt32.json +231 -0
- package/fixtures/erwartet/karte-gptom-ios.blatt48.json +231 -0
- package/fixtures/erwartet/karte-gptom.blatt32.json +231 -0
- package/fixtures/erwartet/karte-gptom.blatt48.json +231 -0
- package/fixtures/erwartet/karte-hobex-cloud.blatt32.json +201 -0
- package/fixtures/erwartet/karte-hobex-cloud.blatt48.json +201 -0
- package/fixtures/erwartet/karte-hobex-hps.blatt32.json +225 -0
- package/fixtures/erwartet/karte-hobex-hps.blatt48.json +225 -0
- package/fixtures/erwartet/karte-mypos.blatt32.json +255 -0
- package/fixtures/erwartet/karte-mypos.blatt48.json +243 -0
- package/fixtures/erwartet/karte-stripe-eps.blatt32.json +195 -0
- package/fixtures/erwartet/karte-stripe-eps.blatt48.json +195 -0
- package/fixtures/erwartet/karte-stripe.blatt32.json +213 -0
- package/fixtures/erwartet/karte-stripe.blatt48.json +213 -0
- package/fixtures/erwartet/karte-sumup.blatt32.json +219 -0
- package/fixtures/erwartet/karte-sumup.blatt48.json +207 -0
- package/fixtures/erwartet/langer-artikelname.blatt32.json +177 -0
- package/fixtures/erwartet/langer-artikelname.blatt48.json +171 -0
- package/fixtures/erwartet/logo-probe-hoch.raster32.txt +120 -0
- package/fixtures/erwartet/logo-probe.raster32.txt +54 -0
- package/fixtures/erwartet/null-ausfall.blatt32.json +207 -0
- package/fixtures/erwartet/null-ausfall.blatt48.json +189 -0
- package/fixtures/erwartet/null-ausfall.grid32.txt +2 -0
- package/fixtures/erwartet/null-ausfall.grid48.txt +2 -0
- package/fixtures/erwartet/null-jahr.blatt32.json +213 -0
- package/fixtures/erwartet/null-jahr.blatt48.json +189 -0
- package/fixtures/erwartet/null-jahr.grid32.txt +2 -0
- package/fixtures/erwartet/null-jahr.grid48.txt +2 -0
- package/fixtures/erwartet/null-monat.blatt32.json +207 -0
- package/fixtures/erwartet/null-monat.blatt48.json +189 -0
- package/fixtures/erwartet/null-monat.grid32.txt +2 -0
- package/fixtures/erwartet/null-monat.grid48.txt +2 -0
- package/fixtures/erwartet/null-pruef.blatt32.json +207 -0
- package/fixtures/erwartet/null-pruef.blatt48.json +189 -0
- package/fixtures/erwartet/null-pruef.grid32.txt +2 -0
- package/fixtures/erwartet/null-pruef.grid48.txt +2 -0
- package/fixtures/erwartet/null-schluss.blatt32.json +207 -0
- package/fixtures/erwartet/null-schluss.blatt48.json +189 -0
- package/fixtures/erwartet/null-schluss.grid32.txt +2 -0
- package/fixtures/erwartet/null-schluss.grid48.txt +2 -0
- package/fixtures/erwartet/null-start.blatt32.json +207 -0
- package/fixtures/erwartet/null-start.blatt48.json +189 -0
- package/fixtures/erwartet/null-start.grid32.txt +2 -0
- package/fixtures/erwartet/null-start.grid48.txt +2 -0
- package/fixtures/erwartet/rabatt-chef-trinkgeld.blatt32.json +213 -0
- package/fixtures/erwartet/rabatt-chef-trinkgeld.blatt48.json +207 -0
- package/fixtures/erwartet/rabatt-einfach.blatt32.json +183 -0
- package/fixtures/erwartet/rabatt-einfach.blatt48.json +177 -0
- package/fixtures/erwartet/rabatt-trinkgeld.blatt32.json +213 -0
- package/fixtures/erwartet/rabatt-trinkgeld.blatt48.json +207 -0
- package/fixtures/erwartet/rabatt-wertgutschein.blatt32.json +219 -0
- package/fixtures/erwartet/rabatt-wertgutschein.blatt48.json +213 -0
- package/fixtures/erwartet/rabattzeilen.blatt32.json +201 -0
- package/fixtures/erwartet/rabattzeilen.blatt48.json +195 -0
- package/fixtures/erwartet/signaturausfall-verkauf.blatt32.json +195 -0
- package/fixtures/erwartet/signaturausfall-verkauf.blatt48.json +183 -0
- package/fixtures/erwartet/storno-rabatt.blatt32.json +249 -0
- package/fixtures/erwartet/storno-rabatt.blatt48.json +237 -0
- package/fixtures/erwartet/storno-rabatt.grid32.txt +2 -0
- package/fixtures/erwartet/storno-rabatt.grid48.txt +2 -0
- package/fixtures/erwartet/storno-teil.blatt32.json +207 -0
- package/fixtures/erwartet/storno-teil.blatt48.json +201 -0
- package/fixtures/erwartet/storno-teil.grid32.txt +2 -0
- package/fixtures/erwartet/storno-teil.grid48.txt +2 -0
- package/fixtures/erwartet/storno-voll.blatt32.json +219 -0
- package/fixtures/erwartet/storno-voll.blatt48.json +213 -0
- package/fixtures/erwartet/storno-voll.grid32.txt +2 -0
- package/fixtures/erwartet/storno-voll.grid48.txt +2 -0
- package/fixtures/erwartet/testkasse-verkauf.blatt32.json +225 -0
- package/fixtures/erwartet/testkasse-verkauf.blatt48.json +219 -0
- package/fixtures/erwartet/testkasse-verkauf.grid32.txt +5 -1
- package/fixtures/erwartet/testkasse-verkauf.grid48.txt +5 -1
- package/fixtures/erwartet/testsignatur-verkauf.blatt32.json +237 -0
- package/fixtures/erwartet/testsignatur-verkauf.blatt48.json +219 -0
- package/fixtures/erwartet/testsignatur-verkauf.grid32.txt +5 -1
- package/fixtures/erwartet/testsignatur-verkauf.grid48.txt +5 -1
- package/fixtures/erwartet/training.blatt32.json +237 -0
- package/fixtures/erwartet/training.blatt48.json +219 -0
- package/fixtures/erwartet/training.grid32.txt +2 -0
- package/fixtures/erwartet/training.grid48.txt +2 -0
- package/fixtures/erwartet/verkauf-bar.blatt32.json +177 -0
- package/fixtures/erwartet/verkauf-bar.blatt48.json +171 -0
- package/fixtures/erwartet/verkauf-karte.blatt32.json +177 -0
- package/fixtures/erwartet/verkauf-karte.blatt48.json +171 -0
- package/fixtures/erwartet/verkauf-kleinunternehmer.blatt32.json +183 -0
- package/fixtures/erwartet/verkauf-kleinunternehmer.blatt48.json +177 -0
- package/fixtures/hobex-hps-codes.json +1 -1
- package/fixtures/kasse-settings-standard.json +1 -1
- package/fixtures/kasse-texte.json +1 -1
- package/fixtures/manifest.json +109 -43
- package/fixtures/oberflaeche.json +87 -1
- package/fixtures/rechnung-api-beispiele/credit-fehler-grund.json +24 -0
- package/fixtures/rechnung-api-beispiele/credit-ok.json +20 -0
- package/fixtures/rechnung-api-beispiele/customer-fehler-uid.json +25 -0
- package/fixtures/rechnung-api-beispiele/customer-get-fehler-beide.json +15 -0
- package/fixtures/rechnung-api-beispiele/customer-ok.json +20 -0
- package/fixtures/rechnung-api-beispiele/customer-search-fehler-leer.json +14 -0
- package/fixtures/rechnung-api-beispiele/issue-brutto-20.json +27 -0
- package/fixtures/rechnung-api-beispiele/issue-fehler-cent.json +26 -0
- package/fixtures/rechnung-api-beispiele/issue-fehler-menge.json +26 -0
- package/fixtures/rechnung-api-beispiele/issue-fehler-negativ.json +26 -0
- package/fixtures/rechnung-api-beispiele/issue-fehler-satz.json +26 -0
- package/fixtures/rechnung-api-beispiele/issue-fehler-unbekannt.json +27 -0
- package/fixtures/rechnung-api-beispiele/issue-gemischt.json +33 -0
- package/fixtures/rechnung-api-beispiele/issue-kleinunternehmer.json +27 -0
- package/fixtures/rechnung-api-beispiele/issue-netto-20.json +28 -0
- package/fixtures/rechnung-api-beispiele/issue-rabatt.json +28 -0
- package/fixtures/rechnung-api.schema.json +672 -0
- package/package.json +12 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,104 @@ Was vor 0.7.0 geschah, steht in der Commit-Historie (`git log`); ab hier wird
|
|
|
4
4
|
es hier geführt. Ein Eintrag nennt die Änderung **und ihren Grund** —
|
|
5
5
|
nur der Grund überlebt den nächsten Umbau.
|
|
6
6
|
|
|
7
|
+
## 0.15.0
|
|
8
|
+
|
|
9
|
+
### Rechnungs-API: Rechnungen statt Belege, per `api_key`
|
|
10
|
+
|
|
11
|
+
**Anlass:** Fremdsysteme (Shops, Buchhaltungssoftware) konnten Rechnungen nur
|
|
12
|
+
über die Endpunkte des Panels anlegen — mit Anmeldung als Mensch, als Entwurf,
|
|
13
|
+
ohne geprüfte Eingabe und ohne Schutz vor einer doppelt ausgestellten Rechnung
|
|
14
|
+
nach einem Zeitlimit. Eine festgeschriebene Rechnung lässt sich aber nur per
|
|
15
|
+
Gutschrift zurücknehmen; ein Doppel ist also teuer.
|
|
16
|
+
|
|
17
|
+
- Neuer Unterpfad `@kreiseck/kasseneck-api/rechnung` mit `createRechnungApi`:
|
|
18
|
+
Kunden (`createCustomer`, `getCustomer`, `updateCustomer`, `searchCustomers`),
|
|
19
|
+
Rechnungen (`issueInvoice`, `cancelInvoice`, `createCreditNote`, `getInvoice`,
|
|
20
|
+
`listInvoices`) und Dateien (`getInvoicePdf`, `getInvoiceXml`).
|
|
21
|
+
- Anmeldung `rechnungKeyAuth`: Kontoschlüssel als Bearer, **ohne**
|
|
22
|
+
Kassen-Token — eine Rechnung entsteht am Konto, nicht an einer Kasse. Ein
|
|
23
|
+
Partner-Schlüssel oder Kassen-Token wird ohne Netzaufruf abgewiesen.
|
|
24
|
+
- Der Vertrag steht als Daten in `src/rechnung/vertrag.ts` und wird als
|
|
25
|
+
`fixtures/rechnung-api.schema.json` ausgeliefert (`npm run fixtures:rechnung`),
|
|
26
|
+
dazu Beispielanfragen unter `fixtures/rechnung-api-beispiele/`. Grund: das
|
|
27
|
+
Backend und der Dart-Zwilling prüfen gegen dieselbe Datei — die Feldliste
|
|
28
|
+
kann nicht an drei Stellen auseinanderlaufen.
|
|
29
|
+
- `fixtures/oberflaeche.json` führt die elf Aufrufe und einen Abschnitt
|
|
30
|
+
`rechnung` (Fehlercodes, Gutschrift-Gründe, Steuerschemata).
|
|
31
|
+
- `getInvoiceXml` liefert das XML als Text im gewohnten Umschlag statt als rohe
|
|
32
|
+
Datei: so bleibt `einvoice_incomplete` ein gewöhnlicher Fehler mit
|
|
33
|
+
`missing[]`, und der Transport braucht keinen dritten Leseweg.
|
|
34
|
+
|
|
35
|
+
## 0.14.0
|
|
36
|
+
|
|
37
|
+
### Das Beleg-Blatt: ein Beleg, der überall gleich aussieht
|
|
38
|
+
|
|
39
|
+
**Anlass:** Derselbe Beleg sah in der App, am Bon, in der Web-Kasse, im Panel
|
|
40
|
+
und im PDF verschieden aus. Das Raster war als einzige Wahrheit gedacht, aber
|
|
41
|
+
jeder Zeichner setzte Rahmen, Logo und QR selbst: das Panel stellte das Logo
|
|
42
|
+
über den Testkassen-Rahmen, das PDF legte es darauf, die App zeigte keins, der
|
|
43
|
+
Bon druckte Warnungen invers und doppelt hoch.
|
|
44
|
+
|
|
45
|
+
- `renderReceiptGrid` gibt Aufdrucke als drei Rasterzeilen aus (`====`, Text,
|
|
46
|
+
`====`). ESC/POS und ePOS drucken sie als normale fette Zeilen — keine doppelte
|
|
47
|
+
Höhe, kein Invertieren mehr. `grid32`/`grid48` der Belege mit Aufdruck ändern
|
|
48
|
+
sich, das Zeilenmodell nicht.
|
|
49
|
+
- Bekannter Unterschied, bleibt so: ESC/POS druckt `EUR` statt `€` (die
|
|
50
|
+
Ein-Byte-Codepage des Bondruckers kennt das Zeichen nicht). Bildschirm, PDF
|
|
51
|
+
und ePOS zeigen `€`; die Zeilen sind dadurch am Bon an diesen Stellen anders
|
|
52
|
+
gefüllt, das Raster bleibt gleich breit.
|
|
53
|
+
- Neu `belegBlatt(layout, { zeichen, logo, marke, qrGroesse })`: Reihenfolge
|
|
54
|
+
(Aufdrucke oben, Leerzeile, Logo, Leerzeile, Beleg, Marke), Logo-Maß je Stufe
|
|
55
|
+
S/M/L/XL (nie hochgerechnet), QR-Anteil wie am Drucker.
|
|
56
|
+
- Ein QR-Inhalt, der in keine QR-Version passt (Korrektur M, mehr als 2331
|
|
57
|
+
Byte), bekommt im Blatt den Anteil 0, statt dass `belegBlatt` wirft. ESC/POS
|
|
58
|
+
und ePOS lassen den QR dann weg und melden es über `qrFehler`; der Beleg steht
|
|
59
|
+
ohne QR. Die Bildschirm-Ansicht ruft `renderQr` weiter mit der Nutzlast, damit
|
|
60
|
+
die Oberfläche den fehlenden QR anzeigen kann (Papierbeleg-Hinweis). **Grund:** Ein Wurf riss jeden Zeichner mit — die Bon-Ansicht der
|
|
61
|
+
Web-Kasse fiel ganz aus, Bon und PDF ebenso. Neu `qrPasstInVersion(nutzlast)`
|
|
62
|
+
(`./printing`); `qrModulAnzahl` wirft weiter.
|
|
63
|
+
- Neu `logoRaster` (RGBA → einfarbiges Rasterbild), `escPosRasterBild`,
|
|
64
|
+
`eposBildXml`; `escPosLayoutBytes` und `eposPrintXml` nehmen `logo` und `marke`.
|
|
65
|
+
- Neu `BelegBlattView` / `BelegBlattZeilen` (`./react`); `ReceiptLayoutView` ist
|
|
66
|
+
`@deprecated`. `BelegBlattView` zeigt ein Logo ueber 4096x4096px (oder 0)
|
|
67
|
+
ebenso wenig wie ein nicht geladenes -- neu `LOGO_PIXEL_MAX`,
|
|
68
|
+
`logoPixelZulaessig` (`./receipt`). **Grund:** Bildschirm und Bon zeigen
|
|
69
|
+
dasselbe Logo; das Druck-Kit lehnt ein zu grosses Logo beim Rastern fuer
|
|
70
|
+
den Bon schon ab (dieselbe Grenze), der Bildschirm bisher nicht -- ein
|
|
71
|
+
5000x1200px-Logo erschien am Bildschirm und im PDF, aber nie auf dem
|
|
72
|
+
gedruckten Beleg.
|
|
73
|
+
- Neu `ReceiptWithCompany.logoStufe` (aus `logo_skala` der Beleg-Antwort,
|
|
74
|
+
Vorgabe `M`): Panel und App kannten die Logo-Stufe des Betriebs bisher nicht.
|
|
75
|
+
- `createPrintJob` nimmt `logo` und `marke`: der Netzwerk-Drucker (Connect)
|
|
76
|
+
druckt dasselbe Blatt wie USB, Bluetooth und ePOS direkt. Neu
|
|
77
|
+
`rasterZeilenBase64` (gemeinsam für ePOS-`<image>` und den Druckjob).
|
|
78
|
+
- Goldens `erwartet/<name>.blatt32.json`/`.blatt48.json`,
|
|
79
|
+
`erwartet/logo-probe.raster32.txt` (mit Teiltransparenz) und
|
|
80
|
+
`erwartet/logo-probe-hoch.raster32.txt` (höhenbegrenzt) für den Dart-Zwilling.
|
|
81
|
+
- `escPosRasterBild` wirft bei einer Bildhöhe über 65535 Punkten (`GS v 0` trägt
|
|
82
|
+
die Höhe in zwei Bytes).
|
|
83
|
+
|
|
84
|
+
### Achtung: Brüche
|
|
85
|
+
|
|
86
|
+
- **Aufdrucke im Raster.** `renderReceiptGrid` gibt jeden Aufdruck als drei
|
|
87
|
+
Zeilen `kind:'banner'` aus (`====`, Text, `====`). *Umstellen:* eigene
|
|
88
|
+
Rahmen oder Sonderstile für Aufdrucke entfernen (sie stünden sonst doppelt)
|
|
89
|
+
und nicht annehmen, dass die erste `banner`-Zeile die einzige ist — der Text
|
|
90
|
+
steht in der mittleren.
|
|
91
|
+
- **`ReceiptWithCompany.logoStufe` ist Pflicht.** `getReceiptWithCompany` füllt
|
|
92
|
+
es selbst. *Umstellen:* von Hand gebaute Objekte (Tests, Vorschauen) brauchen
|
|
93
|
+
`logoStufe: 'M'`.
|
|
94
|
+
- **QR-Vorgabe `auto` deckelt bei 6 Punkten je Modul (vorher 4)** — in npm und
|
|
95
|
+
Dart dasselbe. Am ESC/POS-Bon wird der QR ohne ausdrückliche Wahl größer
|
|
96
|
+
(80 mm: rund 55 % statt 37 % der Breite). *Umstellen:* wer die alte Größe
|
|
97
|
+
will, stellt `qrGroesse: 'klein'`.
|
|
98
|
+
- **Nativer ESC/POS-QR mit Fehlerkorrektur M (vorher L)**, wie ePOS, Bildweg
|
|
99
|
+
und Blatt — der Kasten am Bildschirm ist damit genau der gedruckte QR.
|
|
100
|
+
Manche Nutzlasten brauchen eine Version mehr. *Umstellen:* den alten
|
|
101
|
+
Bytestrom liefert `qrCorrection: 'L'` (zusammen mit `qrGroesse: 'klein'`).
|
|
102
|
+
- **ePOS-Vorgabe `qrGroesse` ist `auto`** (vorher `mittel`). Derselbe Wert,
|
|
103
|
+
kein Byte anders; nur wer die Vorgabe ausliest oder dokumentiert, merkt es.
|
|
104
|
+
|
|
7
105
|
## 0.13.2
|
|
8
106
|
|
|
9
107
|
### Die Paketseite erklaert, wofuer das Paket da ist
|
package/README.md
CHANGED
|
@@ -426,6 +426,70 @@ app.post('/kasseneck-webhook', express.raw({ type: '*/*' }), async (req, res) =>
|
|
|
426
426
|
});
|
|
427
427
|
```
|
|
428
428
|
|
|
429
|
+
## Rechnungs-API (`./rechnung`)
|
|
430
|
+
|
|
431
|
+
Für Shops, Buchhaltungs- und Branchensoftware: **Rechnungen** (§ 11 UStG) —
|
|
432
|
+
keine Belege — mit dem `api_key` eines Kontos ausstellen. Eine Rechnung ist
|
|
433
|
+
nach dem Aufruf **festgeschrieben**: sie trägt ihre fortlaufende Nummer, ist
|
|
434
|
+
unveränderlich und lässt sich nur noch per Gutschrift korrigieren.
|
|
435
|
+
|
|
436
|
+
**Was die Endpunkte tun, steht in der Referenz** — `docs/api/rechnungen.md`
|
|
437
|
+
im Backend. Hier steht, wie man den Client benutzt. Der Schlüssel gehört auf
|
|
438
|
+
einen **Server**.
|
|
439
|
+
|
|
440
|
+
```ts
|
|
441
|
+
import { createRechnungApi, istRechnungFehler } from '@kreiseck/kasseneck-api/rechnung';
|
|
442
|
+
|
|
443
|
+
const rechnungen = createRechnungApi({ apiKey: process.env.KASSENECK_API_KEY! });
|
|
444
|
+
|
|
445
|
+
// 1. Kunde einmal anlegen — externalId ist die eigene Kundennummer.
|
|
446
|
+
let kunde;
|
|
447
|
+
try {
|
|
448
|
+
kunde = await rechnungen.createCustomer({
|
|
449
|
+
type: 'company', name: 'Café Muster GmbH', country: 'AT',
|
|
450
|
+
street: 'Hauptplatz', houseNumber: '3', zip: '1010', city: 'Wien',
|
|
451
|
+
externalId: 'shop-4711',
|
|
452
|
+
});
|
|
453
|
+
} catch (fehler) {
|
|
454
|
+
if (!istRechnungFehler(fehler, 'customer_exists')) throw fehler;
|
|
455
|
+
kunde = await rechnungen.getCustomer({ externalId: 'shop-4711' });
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// 2. Ausstellen. Beträge in ganzen Cent; das Rechnungsdatum setzt der Server.
|
|
459
|
+
const { invoice, replayed } = await rechnungen.issueInvoice({
|
|
460
|
+
idempotencyKey: `bestellung-${bestellnummer}`, // gleiche Bestellung = gleiche Rechnung
|
|
461
|
+
customerId: kunde.id,
|
|
462
|
+
taxScheme: 'normal',
|
|
463
|
+
priceMode: 'net',
|
|
464
|
+
serviceStart: '2026-09-14',
|
|
465
|
+
items: [{ description: 'Beratung', quantity: 2, unit: 'Std', unitPriceCents: 5000, vatRate: 20 }],
|
|
466
|
+
});
|
|
467
|
+
// invoice.number, invoice.totals.grossCents (12000), invoice.statusUrl
|
|
468
|
+
|
|
469
|
+
// 3. Dateien holen.
|
|
470
|
+
const pdf = await rechnungen.getInvoicePdf(invoice.id); // Uint8Array, mit Factur-X
|
|
471
|
+
const xml = await rechnungen.getInvoiceXml(invoice.id, 'ubl'); // Peppol-UBL als Text
|
|
472
|
+
|
|
473
|
+
// 4. Korrigieren — nur per Gutschrift.
|
|
474
|
+
await rechnungen.createCreditNote({
|
|
475
|
+
idempotencyKey: `nachlass-${bestellnummer}`,
|
|
476
|
+
invoiceId: invoice.id,
|
|
477
|
+
reason: 'price_reduction',
|
|
478
|
+
items: [{ description: 'Nachlass Beratung', quantity: 1, unitPriceCents: 2000, vatRate: 20 }],
|
|
479
|
+
});
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
**Nach einem Zeitlimit mit demselben `idempotencyKey` wiederholen**, nie mit
|
|
483
|
+
einem neuen: dann kommt die schon ausgestellte Rechnung zurück
|
|
484
|
+
(`replayed: true`). Derselbe Schlüssel mit anderen Daten ergibt
|
|
485
|
+
`idempotency_conflict`.
|
|
486
|
+
|
|
487
|
+
Formfehler kommen als `validation` mit Feldpfaden (`rechnungFeldFehler(fehler)`
|
|
488
|
+
→ `[{ field: 'items[0].vatRate', message }]`). Der Vertrag selbst liegt als
|
|
489
|
+
Daten im Paket (`RECHNUNG_ANFRAGEN`) und als JSON Schema unter
|
|
490
|
+
`@kreiseck/kasseneck-api/fixtures/rechnung-api.schema.json`; das Backend prüft
|
|
491
|
+
gegen genau diese Datei.
|
|
492
|
+
|
|
429
493
|
## Unterpfade
|
|
430
494
|
|
|
431
495
|
| Unterpfad | Inhalt |
|
|
@@ -437,6 +501,7 @@ app.post('/kasseneck-webhook', express.raw({ type: '*/*' }), async (req, res) =>
|
|
|
437
501
|
| `…/register` | Anmeldung der Browser-Kasse: Gerät koppeln und entkoppeln, Benutzer auflisten, per PIN anmelden, Sitzung erneuern und beenden. |
|
|
438
502
|
| `…/kasse` | Kachel-Kasse: Kassen-Einstellungen (betriebsweit / je Gerät), Artikelgruppen und Artikel für Kacheln, Rabattverteilung je Steuersatz, Reichweiten der Kassen-Rechte |
|
|
439
503
|
| `…/partner` | Partner-API: Betriebe anlegen, FinanzOnline-Link, Signatur, Kassen, Zugangsdaten, Webhooks samt Signaturprüfung. **Gehört auf einen Server.** |
|
|
504
|
+
| `…/rechnung` | Rechnungs-API: Kunden anlegen und suchen, Rechnungen festgeschrieben ausstellen, Gutschrift und Storno, PDF und E-Rechnung-XML; der Vertrag als Daten. **Gehört auf einen Server.** |
|
|
440
505
|
| `…/react` | Dünner React-Adapter, der ein Beleg-Layout zeichnet. Braucht React. |
|
|
441
506
|
| `…/fixtures/*` | Golden-Belege (JSON): Eingaben `belege/<name>.json`, zugesagte Zeilenausgabe `erwartet/<name>.lines.json`, `manifest.json` mit Prüfsummen — dieselben Dateien prüfen Backend, Browser-Kasse und Flutter-Paket. |
|
|
442
507
|
|
|
@@ -460,8 +525,9 @@ const mass = qrGroesseFuer({ nutzlast: beleg.qr, papierbreitePunkte: QR_DRUCK_PU
|
|
|
460
525
|
|
|
461
526
|
Am Belegweg passiert das von selbst. `qrGroesse` ist ein **Deckel**, keine
|
|
462
527
|
Vorgabe: gedruckt wird die größte Größe, die noch passt, höchstens aber der
|
|
463
|
-
Deckel. `auto` (Vorgabe) deckelt
|
|
464
|
-
|
|
528
|
+
Deckel. `auto` (Vorgabe) deckelt bei 6 Punkten je Modul — wie im Dart-Zwilling
|
|
529
|
+
und am Epson-Weg; `klein` deckelt bei 4. Alle Druckwege setzen den QR mit
|
|
530
|
+
Fehlerkorrektur M.
|
|
465
531
|
|
|
466
532
|
```ts
|
|
467
533
|
import { escPosLayoutErgebnis } from '@kreiseck/kasseneck-api/receipt';
|
|
@@ -474,8 +540,8 @@ const { bytes, qrFehler, qrAusweich } = escPosLayoutErgebnis(layout, {
|
|
|
474
540
|
```
|
|
475
541
|
|
|
476
542
|
Der Epson-Weg (`eposPrintXml` / `eposDirectPrint`) rechnet genauso;
|
|
477
|
-
`eposPrintXmlErgebnis` gibt dort `{ xml, qrFehler, qrAusweich }`.
|
|
478
|
-
|
|
543
|
+
`eposPrintXmlErgebnis` gibt dort `{ xml, qrFehler, qrAusweich }`. Die Vorgabe
|
|
544
|
+
ist auch dort `auto`.
|
|
479
545
|
|
|
480
546
|
`qrFehler` heißt „Beleg ohne QR" — das gehört dem Kunden gesagt. `qrAusweich`
|
|
481
547
|
heißt „gedruckt, aber der eingestellte Weg taugt für dieses Gerät nicht" — das
|
|
@@ -483,6 +549,30 @@ gehört dem Chef gesagt. Den Bildweg fährt das Paket nur mit einem `qrMatrix`,
|
|
|
483
549
|
das die Nutzlast in ein fertiges Raster übersetzt: hier wird bewusst weder ein
|
|
484
550
|
QR gerechnet noch ein Bild verarbeitet.
|
|
485
551
|
|
|
552
|
+
## Das Beleg-Blatt: überall derselbe Beleg
|
|
553
|
+
|
|
554
|
+
Bildschirm, Bon, ePOS und PDF setzen dasselbe **Blatt**: Rasterzeilen, Firmenlogo,
|
|
555
|
+
QR und die Marke „erstellt mit Kasseneck", mit Größen als Anteil der Blattbreite
|
|
556
|
+
und in Zeilen (eine Zeile = zwei Zeichenbreiten).
|
|
557
|
+
|
|
558
|
+
```tsx
|
|
559
|
+
import { BelegBlattView } from '@kreiseck/kasseneck-api/react';
|
|
560
|
+
|
|
561
|
+
<BelegBlattView layout={layout} logo={{ url: company.logoUrl, stufe: 'M' }} marke={company.showKreiseckLogo} renderQr={(d) => <QrSvg data={d} />} />
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
```ts
|
|
565
|
+
import { escPosLayoutBytes, logoMass, logoRaster } from '@kreiseck/kasseneck-api/receipt';
|
|
566
|
+
|
|
567
|
+
const mass = logoMass({ stufe: 'M', pxBreite: bild.width, pxHoehe: bild.height }, 48);
|
|
568
|
+
const raster = logoRaster(imageData.data, bild.width, bild.height, mass, 48);
|
|
569
|
+
escPosLayoutBytes(layout, { paperSize: 'mm80', logo: { stufe: 'M', pxBreite: bild.width, pxHoehe: bild.height, raster }, marke: true });
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
Logo-Stufen: S 42 % × 5 Zeilen, M 62 % × 8, L 80 % × 12, XL 94 % × 16 — eingepasst,
|
|
573
|
+
nie hochgerechnet. Der Aufdruck (TESTKASSE, STORNOBELEG …) ist ein Rahmen aus
|
|
574
|
+
`=`-Zeilen, auf jedem Weg gleich.
|
|
575
|
+
|
|
486
576
|
## Hobex HPS über Kasseneck Connect
|
|
487
577
|
|
|
488
578
|
Ein Browser hat weiterhin keine rohen TCP-Sockets — ein **direkter**
|
|
@@ -516,7 +606,8 @@ Android-SDKs ohne Entsprechung hier.
|
|
|
516
606
|
## Was hier grundsätzlich nicht dazugehört
|
|
517
607
|
|
|
518
608
|
Die Druckeransteuerung selbst (dieses Paket erzeugt die Bytes, es verschickt
|
|
519
|
-
sie nicht)
|
|
609
|
+
sie nicht) und die PDF-Erzeugung. Bilder dekodieren (PNG/JPEG): das Paket
|
|
610
|
+
rastert fertige RGBA-Pixel, das Laden des Bilds bleibt bei der Anwendung.
|
|
520
611
|
|
|
521
612
|
## Entwicklung
|
|
522
613
|
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* umhuellt, muss ihn weiterhin absetzen koennen.
|
|
14
14
|
*/
|
|
15
15
|
import type { TransportBodyFields } from './transport.js';
|
|
16
|
-
export declare const AUFRUFE: readonly ["activateCashregister", "cancelReceipt", "createCustomerCashregister", "createPartnerCustomer", "checkPartnerCustomerEmail", "createPartnerWebhook", "createPaymentLinkStripe", "createPrintJob", "createReceipt", "deletePartnerWebhook", "downloadDailyReport", "downloadReport", "endRegisterSession", "financeWebService", "generateFullReceiptId", "getCustomerCredentials", "getCustomerSignatureStatus", "getFirstReceiptDate", "getKasseSettings", "getPartnerCustomer", "getPartnerInfo", "getPrintJob", "getReceipt", "hobexPayApi", "hobexRefundApi", "listCustomerCashregisters", "listMyArticleGroups", "listMyArticles", "listMyCashregisters", "listMyPrinters", "listMyReceipts", "listMyTipRecipients", "listPartnerCustomers", "listPartnerWebhookDeliveries", "listPartnerWebhooks", "listRegisterUsersForDevice", "listRegisterSessionsForDevice", "pairRegisterDevice", "registerPinLogin", "registerUserLogin", "renewRegisterSession", "requestCustomerSignature", "sendPartnerCustomerFonLink", "sendPartnerWebhookTest", "sendReceiptEmail", "setMyKasseSettings", "setMyRegisterDeviceSettings", "stripeCaptureIntent", "unpairRegisterDevice", "rotatePartnerWebhookSecret", "updatePartnerWebhook"];
|
|
16
|
+
export declare const AUFRUFE: readonly ["activateCashregister", "cancelInvoice", "cancelReceipt", "createCreditNote", "createCustomer", "createCustomerCashregister", "createPartnerCustomer", "checkPartnerCustomerEmail", "createPartnerWebhook", "createPaymentLinkStripe", "createPrintJob", "createReceipt", "deletePartnerWebhook", "downloadDailyReport", "downloadReport", "endRegisterSession", "financeWebService", "generateFullReceiptId", "getCustomer", "getCustomerCredentials", "getCustomerSignatureStatus", "getFirstReceiptDate", "getInvoice", "getInvoicePdf", "getInvoiceXml", "getKasseSettings", "getPartnerCustomer", "getPartnerInfo", "getPrintJob", "getReceipt", "hobexPayApi", "hobexRefundApi", "issueInvoice", "listCustomerCashregisters", "listInvoices", "listMyArticleGroups", "listMyArticles", "listMyCashregisters", "listMyPrinters", "listMyReceipts", "listMyTipRecipients", "listPartnerCustomers", "listPartnerWebhookDeliveries", "listPartnerWebhooks", "listRegisterUsersForDevice", "listRegisterSessionsForDevice", "pairRegisterDevice", "registerPinLogin", "registerUserLogin", "renewRegisterSession", "requestCustomerSignature", "searchCustomers", "sendPartnerCustomerFonLink", "sendPartnerWebhookTest", "sendReceiptEmail", "setMyKasseSettings", "setMyRegisterDeviceSettings", "stripeCaptureIntent", "unpairRegisterDevice", "rotatePartnerWebhookSecret", "updateCustomer", "updatePartnerWebhook"];
|
|
17
17
|
export type Aufruf = typeof AUFRUFE[number];
|
|
18
18
|
/** Wie [KasseneckTransport], nur mit bekanntem Aufrufnamen. Nicht exportiert nach aussen. */
|
|
19
19
|
export type InternerTransport = <T = unknown>(functionName: Aufruf, params?: Record<string, unknown>, extraBodyFields?: TransportBodyFields, secretParams?: readonly string[]) => Promise<T>;
|
|
@@ -3,7 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.AUFRUFE = void 0;
|
|
4
4
|
exports.AUFRUFE = [
|
|
5
5
|
'activateCashregister',
|
|
6
|
+
'cancelInvoice',
|
|
6
7
|
'cancelReceipt',
|
|
8
|
+
'createCreditNote',
|
|
9
|
+
'createCustomer',
|
|
7
10
|
'createCustomerCashregister',
|
|
8
11
|
'createPartnerCustomer',
|
|
9
12
|
'checkPartnerCustomerEmail',
|
|
@@ -17,9 +20,13 @@ exports.AUFRUFE = [
|
|
|
17
20
|
'endRegisterSession',
|
|
18
21
|
'financeWebService',
|
|
19
22
|
'generateFullReceiptId',
|
|
23
|
+
'getCustomer',
|
|
20
24
|
'getCustomerCredentials',
|
|
21
25
|
'getCustomerSignatureStatus',
|
|
22
26
|
'getFirstReceiptDate',
|
|
27
|
+
'getInvoice',
|
|
28
|
+
'getInvoicePdf',
|
|
29
|
+
'getInvoiceXml',
|
|
23
30
|
'getKasseSettings',
|
|
24
31
|
'getPartnerCustomer',
|
|
25
32
|
'getPartnerInfo',
|
|
@@ -27,7 +34,9 @@ exports.AUFRUFE = [
|
|
|
27
34
|
'getReceipt',
|
|
28
35
|
'hobexPayApi',
|
|
29
36
|
'hobexRefundApi',
|
|
37
|
+
'issueInvoice',
|
|
30
38
|
'listCustomerCashregisters',
|
|
39
|
+
'listInvoices',
|
|
31
40
|
'listMyArticleGroups',
|
|
32
41
|
'listMyArticles',
|
|
33
42
|
'listMyCashregisters',
|
|
@@ -44,6 +53,7 @@ exports.AUFRUFE = [
|
|
|
44
53
|
'registerUserLogin',
|
|
45
54
|
'renewRegisterSession',
|
|
46
55
|
'requestCustomerSignature',
|
|
56
|
+
'searchCustomers',
|
|
47
57
|
'sendPartnerCustomerFonLink',
|
|
48
58
|
'sendPartnerWebhookTest',
|
|
49
59
|
'sendReceiptEmail',
|
|
@@ -52,5 +62,6 @@ exports.AUFRUFE = [
|
|
|
52
62
|
'stripeCaptureIntent',
|
|
53
63
|
'unpairRegisterDevice',
|
|
54
64
|
'rotatePartnerWebhookSecret',
|
|
65
|
+
'updateCustomer',
|
|
55
66
|
'updatePartnerWebhook',
|
|
56
67
|
];
|
|
@@ -2,6 +2,7 @@ import { ReceiptType, type ReceiptTypeKey, KeckPaymentMethod, type KeckPaymentMe
|
|
|
2
2
|
import { type Receipt, type ReceiptCompany, type ReceiptItem, type Voucher, type ReceiptSummary, type ReportMonth, type CancellationItem, type CancellationOf, type CancellationReason } from '../models/index.js';
|
|
3
3
|
import type { InternerTransport } from './aufrufe.js';
|
|
4
4
|
import type { Pruefangaben, ReceiptLayout } from '../receipt/layout.js';
|
|
5
|
+
import type { LogoStufe } from '../receipt/blatt.js';
|
|
5
6
|
/**
|
|
6
7
|
* Beleg-Endpunkte — Zwilling der Beleg-Aufrufe in
|
|
7
8
|
* kasseneck_api/lib/kasseneck_api.dart.
|
|
@@ -168,6 +169,12 @@ export interface ReceiptWithCompany {
|
|
|
168
169
|
* fuer Clients, die das Layout selbst bauen; null bei altem Backend.
|
|
169
170
|
*/
|
|
170
171
|
pruefangaben: Pruefangaben | null;
|
|
172
|
+
/**
|
|
173
|
+
* Groesse des Firmenlogos am Beleg (Kasse-Einstellung `logoSkala` des
|
|
174
|
+
* Betriebs). Bildschirm, Bon und PDF setzen das Logo in genau dieser Stufe;
|
|
175
|
+
* liefert das Backend sie nicht (alt), gilt `M` -- der Bestandswert.
|
|
176
|
+
*/
|
|
177
|
+
logoStufe: LogoStufe;
|
|
171
178
|
}
|
|
172
179
|
/**
|
|
173
180
|
* Gemeinsame Umsetzung aller Belegarten (Zwilling von `_createReceipt`).
|
|
@@ -582,5 +582,6 @@ function belegMitFirmaAusHuelle(daten, functionName) {
|
|
|
582
582
|
kopfId: typeof d.kopfId === 'string' ? d.kopfId : null,
|
|
583
583
|
layout,
|
|
584
584
|
pruefangaben: pa ? { karteRegistriertAm: text(pa.karteRegistriertAm), kasseRegistriertAm: text(pa.kasseRegistriertAm) } : null,
|
|
585
|
+
logoStufe: d.logo_skala === 'S' || d.logo_skala === 'M' || d.logo_skala === 'L' || d.logo_skala === 'XL' ? d.logo_skala : 'M',
|
|
585
586
|
};
|
|
586
587
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { InternerTransport } from '../client/aufrufe.js';
|
|
2
2
|
import type { ReceiptLayout } from '../receipt/layout.js';
|
|
3
|
+
import type { DruckLogo } from '../receipt/layout-escpos.js';
|
|
3
4
|
/**
|
|
4
5
|
* Netzwerk-Bondrucker ueber Epson "Server Direct Print": das Backend fuehrt
|
|
5
6
|
* je Konto Drucker mit einer geheimen Abhol-URL; die Kasse legt Druckjobs
|
|
@@ -46,6 +47,10 @@ export interface CreatePrintJobOptions {
|
|
|
46
47
|
receiptId?: string;
|
|
47
48
|
titel?: string;
|
|
48
49
|
quelle?: string;
|
|
50
|
+
/** Firmenlogo als fertiges Rasterbild (`logoRaster`); der Server dekodiert keine Bilder. */
|
|
51
|
+
logo?: DruckLogo | null;
|
|
52
|
+
/** "erstellt mit Kasseneck" am Ende (Konto-Flag `kreiseck_logo`). */
|
|
53
|
+
marke?: boolean;
|
|
49
54
|
}
|
|
50
55
|
export declare function createPrintJob(rufen: InternerTransport, o: CreatePrintJobOptions): Promise<DruckJob>;
|
|
51
56
|
export declare function getPrintJob(rufen: InternerTransport, o: {
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.listMyPrinters = listMyPrinters;
|
|
4
4
|
exports.createPrintJob = createPrintJob;
|
|
5
5
|
exports.getPrintJob = getPrintJob;
|
|
6
|
+
const index_js_1 = require("../printing/index.js");
|
|
6
7
|
const text = (v) => (typeof v === 'string' && v ? v : null);
|
|
7
8
|
const zahl = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : null);
|
|
8
9
|
async function listMyPrinters(rufen) {
|
|
@@ -27,6 +28,14 @@ async function createPrintJob(rufen, o) {
|
|
|
27
28
|
params.titel = o.titel;
|
|
28
29
|
if (o.quelle)
|
|
29
30
|
params.quelle = o.quelle;
|
|
31
|
+
if (o.logo) {
|
|
32
|
+
params.logo = {
|
|
33
|
+
stufe: o.logo.stufe, pxBreite: o.logo.pxBreite, pxHoehe: o.logo.pxHoehe,
|
|
34
|
+
breite: o.logo.raster.breite, hoehe: o.logo.raster.hoehe, zeilen: (0, index_js_1.rasterZeilenBase64)(o.logo.raster),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
if (o.marke === true)
|
|
38
|
+
params.marke = true;
|
|
30
39
|
const daten = await rufen('createPrintJob', params);
|
|
31
40
|
return { jobId: String(daten?.jobId ?? ''), status: text(daten?.status) ?? 'offen', ergebnis: null };
|
|
32
41
|
}
|
|
@@ -116,8 +116,11 @@ exports.KASSE_TASTEN_STANDARD = Object.freeze({
|
|
|
116
116
|
korbLeeren: ['Mod+C'],
|
|
117
117
|
});
|
|
118
118
|
exports.KASSE_BETRIEB_STANDARD = Object.freeze({
|
|
119
|
-
// Petrol
|
|
120
|
-
|
|
119
|
+
// Das Petrol der Marke: die Aktionsfarbe des Design-Systems (Rolle `brand`).
|
|
120
|
+
// Stand bis September 2026 auf dem Wert des alten Markenhandbuchs,
|
|
121
|
+
// der um 0,07 in OKLab danebenlag. Unsichtbar, aber es war die letzte Stelle
|
|
122
|
+
// im Haus, an der eine zweite Zahl fuer dieselbe Farbe stand.
|
|
123
|
+
logoText: 'K', logoAn: true, logoGroesse: 'M', wasserzeichen: 'anmeldung', farbe: '#136B6B',
|
|
121
124
|
stil: 'klar', schrift: 'M', schriftEinst: 'S', kachelstil: 'streifen', uhr: true,
|
|
122
125
|
sperrbild: true, foto: true, autoAbMin: 0, abNachVerkauf: false, schnellLogin: true,
|
|
123
126
|
preisAnzeigen: true, ustAnzeigen: false, emoji: true, katFarben: true, freiErlaubt: true,
|
|
@@ -24,8 +24,9 @@
|
|
|
24
24
|
* CP437-Plaetze umkodiert (ä = 0x84, ü = 0x81, ß = 0xE1, ...). Zeichen ohne
|
|
25
25
|
* CP437-Platz werden zu `?` — weiterhin ein Byte je Zeichen.
|
|
26
26
|
*
|
|
27
|
-
* Nicht enthalten (bewusst):
|
|
28
|
-
* Druckermodelle, Kassenlade, 1D-Barcodes.
|
|
27
|
+
* Nicht enthalten (bewusst): Bilddekodierung (PNG/JPEG liest die Huelle),
|
|
28
|
+
* Capability-Profile einzelner Druckermodelle, Kassenlade, 1D-Barcodes.
|
|
29
|
+
* Fertige einfarbige Rasterbilder (Logo) gehen ueber [escPosRasterBild].
|
|
29
30
|
*/
|
|
30
31
|
import { type QrModulGroesse } from './qr-groesse.js';
|
|
31
32
|
/** Papierbreite der Bonrolle. */
|
|
@@ -103,6 +104,7 @@ export interface EscPosQrOptions {
|
|
|
103
104
|
* die Regel in `qr-groesse.ts`.
|
|
104
105
|
*/
|
|
105
106
|
size?: QrSize;
|
|
107
|
+
/** Fehlerkorrektur; Vorgabe `M` wie auf allen Druckwegen (siehe `qrCodeBytes`). */
|
|
106
108
|
correction?: QrCorrection;
|
|
107
109
|
/** Deckel fuer die gerechnete Modulgroesse; wirkungslos neben `size`. */
|
|
108
110
|
groesse?: QrModulGroesse;
|
|
@@ -255,6 +257,12 @@ export declare function escPosRow(doc: EscPosDocument, columns: readonly PosColu
|
|
|
255
257
|
* es wird kein Bild uebertragen.
|
|
256
258
|
*
|
|
257
259
|
* Bei Kasseneck-Belegen steht hier der maschinenlesbare RKSV-Code.
|
|
260
|
+
*
|
|
261
|
+
* Fehlerkorrektur ohne Angabe: **M** (bis 0.13: L). Die Groessenrechnung
|
|
262
|
+
* (`qrModulAnzahl`), das Blatt (Anteil am Bildschirm und im PDF), der
|
|
263
|
+
* ePOS-Weg (`level_m`) und der Bildweg rechnen alle mit M — druckte der
|
|
264
|
+
* native Befehl mit L, kaeme fuer manche Nutzlasten ein kleineres Symbol
|
|
265
|
+
* heraus als der Bildschirm zeigt.
|
|
258
266
|
*/
|
|
259
267
|
export declare function qrCodeBytes(text: string, options?: {
|
|
260
268
|
size?: QrSize;
|
|
@@ -266,8 +274,8 @@ export declare function qrCodeBytes(text: string, options?: {
|
|
|
266
274
|
* **gerechneter** Modulgroesse, sofern `options.size` sie nicht festlegt.
|
|
267
275
|
*
|
|
268
276
|
* Ohne `size` entscheidet die Regel aus `qr-groesse.ts`: so gross wie
|
|
269
|
-
* moeglich, gedeckelt durch `options.groesse` (Vorgabe `auto` =
|
|
270
|
-
*
|
|
277
|
+
* moeglich, gedeckelt durch `options.groesse` (Vorgabe `auto` = hoechstens 6
|
|
278
|
+
* Punkte je Modul, wie im Flutter-Zwilling). Passt das Symbol auch mit der
|
|
271
279
|
* Ausnahmegroesse nicht aufs Papier, geht **kein** QR-Befehl hinaus und
|
|
272
280
|
* `doc.qrFehler` sagt warum: der Drucker schneidet ein zu breites Symbol
|
|
273
281
|
* nicht ab, er laesst es weg — ein Befehl, von dem man weiss, dass er nichts
|
|
@@ -300,4 +308,30 @@ export declare function qrRasterPunkte(paperSize: PosPaperSize, moduleAnzahl: nu
|
|
|
300
308
|
groesse?: QrModulGroesse;
|
|
301
309
|
ruhezoneModule?: number;
|
|
302
310
|
}): number;
|
|
311
|
+
/**
|
|
312
|
+
* Einfarbiges Rasterbild in Druckpunkten, zeilenweise: `punkte[y * breite + x]`,
|
|
313
|
+
* 1 = schwarz. Entsteht fuer das Firmenlogo in `logoRaster` (receipt/bild.ts).
|
|
314
|
+
*/
|
|
315
|
+
export interface RasterBild {
|
|
316
|
+
readonly breite: number;
|
|
317
|
+
readonly hoehe: number;
|
|
318
|
+
readonly punkte: Uint8Array;
|
|
319
|
+
}
|
|
320
|
+
/** Die Rasterzeilen als Bytes: MSB zuerst, jede Zeile auf volle Bytes aufgefuellt. */
|
|
321
|
+
export declare function rasterZeilenBytes(bild: RasterBild): Uint8Array;
|
|
322
|
+
/**
|
|
323
|
+
* Die Rasterzeilen als Base64 -- ohne Buffer, laeuft im Browser und in Node.
|
|
324
|
+
* Eine Stelle fuer ePOS-`<image>` und den Druckjob an den Server.
|
|
325
|
+
*/
|
|
326
|
+
export declare function rasterZeilenBase64(bild: RasterBild): string;
|
|
327
|
+
/**
|
|
328
|
+
* Ein Rasterbild (`GS v 0`) -- das Firmenlogo am Bon.
|
|
329
|
+
*
|
|
330
|
+
* Anders als `escPosQrRaster` folgt KEIN Zeilenvorschub: `GS v 0` schiebt das
|
|
331
|
+
* Papier um die Bildhoehe, ein LF danach waere eine zusaetzliche Leerzeile,
|
|
332
|
+
* die Bildschirm und PDF nicht haben. Die Luft um das Logo kommt aus dem Blatt.
|
|
333
|
+
*/
|
|
334
|
+
export declare function escPosRasterBild(doc: EscPosDocument, bild: RasterBild, options?: {
|
|
335
|
+
align?: PosAlign;
|
|
336
|
+
}): void;
|
|
303
337
|
export {};
|
|
@@ -25,8 +25,9 @@
|
|
|
25
25
|
* CP437-Plaetze umkodiert (ä = 0x84, ü = 0x81, ß = 0xE1, ...). Zeichen ohne
|
|
26
26
|
* CP437-Platz werden zu `?` — weiterhin ein Byte je Zeichen.
|
|
27
27
|
*
|
|
28
|
-
* Nicht enthalten (bewusst):
|
|
29
|
-
* Druckermodelle, Kassenlade, 1D-Barcodes.
|
|
28
|
+
* Nicht enthalten (bewusst): Bilddekodierung (PNG/JPEG liest die Huelle),
|
|
29
|
+
* Capability-Profile einzelner Druckermodelle, Kassenlade, 1D-Barcodes.
|
|
30
|
+
* Fertige einfarbige Rasterbilder (Logo) gehen ueber [escPosRasterBild].
|
|
30
31
|
*/
|
|
31
32
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
33
|
exports.encodeEscPosText = encodeEscPosText;
|
|
@@ -49,6 +50,9 @@ exports.qrCodeBytes = qrCodeBytes;
|
|
|
49
50
|
exports.escPosQrCode = escPosQrCode;
|
|
50
51
|
exports.escPosQrRaster = escPosQrRaster;
|
|
51
52
|
exports.qrRasterPunkte = qrRasterPunkte;
|
|
53
|
+
exports.rasterZeilenBytes = rasterZeilenBytes;
|
|
54
|
+
exports.rasterZeilenBase64 = rasterZeilenBase64;
|
|
55
|
+
exports.escPosRasterBild = escPosRasterBild;
|
|
52
56
|
const qr_groesse_js_1 = require("./qr-groesse.js");
|
|
53
57
|
// -------------------------------------------------------------- Befehlsbytes
|
|
54
58
|
// Wortwoertlich aus commands.dart. Die Zahlen sind ASCII-Codes der dortigen
|
|
@@ -603,13 +607,19 @@ function escPosRow(doc, columns) {
|
|
|
603
607
|
* es wird kein Bild uebertragen.
|
|
604
608
|
*
|
|
605
609
|
* Bei Kasseneck-Belegen steht hier der maschinenlesbare RKSV-Code.
|
|
610
|
+
*
|
|
611
|
+
* Fehlerkorrektur ohne Angabe: **M** (bis 0.13: L). Die Groessenrechnung
|
|
612
|
+
* (`qrModulAnzahl`), das Blatt (Anteil am Bildschirm und im PDF), der
|
|
613
|
+
* ePOS-Weg (`level_m`) und der Bildweg rechnen alle mit M — druckte der
|
|
614
|
+
* native Befehl mit L, kaeme fuer manche Nutzlasten ein kleineres Symbol
|
|
615
|
+
* heraus als der Bildschirm zeigt.
|
|
606
616
|
*/
|
|
607
617
|
function qrCodeBytes(text, options = {}) {
|
|
608
618
|
const size = options.size ?? 4;
|
|
609
619
|
if (!istGanzzahl(size) || size < 1 || size > 8) {
|
|
610
620
|
throw new Error('QR-Modulgroesse muss eine Ganzzahl im Bereich 1..8 sein');
|
|
611
621
|
}
|
|
612
|
-
const correction = options.correction ?? '
|
|
622
|
+
const correction = options.correction ?? 'M';
|
|
613
623
|
const stufe = QR_KORREKTUR[correction];
|
|
614
624
|
if (stufe === undefined) {
|
|
615
625
|
throw new Error(`Unbekannte QR-Fehlerkorrektur: ${String(correction)}`);
|
|
@@ -650,8 +660,8 @@ function qrCodeBytes(text, options = {}) {
|
|
|
650
660
|
* **gerechneter** Modulgroesse, sofern `options.size` sie nicht festlegt.
|
|
651
661
|
*
|
|
652
662
|
* Ohne `size` entscheidet die Regel aus `qr-groesse.ts`: so gross wie
|
|
653
|
-
* moeglich, gedeckelt durch `options.groesse` (Vorgabe `auto` =
|
|
654
|
-
*
|
|
663
|
+
* moeglich, gedeckelt durch `options.groesse` (Vorgabe `auto` = hoechstens 6
|
|
664
|
+
* Punkte je Modul, wie im Flutter-Zwilling). Passt das Symbol auch mit der
|
|
655
665
|
* Ausnahmegroesse nicht aufs Papier, geht **kein** QR-Befehl hinaus und
|
|
656
666
|
* `doc.qrFehler` sagt warum: der Drucker schneidet ein zu breites Symbol
|
|
657
667
|
* nicht ab, er laesst es weg — ein Befehl, von dem man weiss, dass er nichts
|
|
@@ -736,9 +746,10 @@ function escPosQrRaster(doc, matrix, options = {}) {
|
|
|
736
746
|
if (!istGanzzahl(punkte) || punkte < 1) {
|
|
737
747
|
throw new Error('punkteJeModul muss eine Ganzzahl >= 1 sein');
|
|
738
748
|
}
|
|
749
|
+
// Modulraster (samt Ruhezone) auf Druckpunkte skaliert -- dieselbe Bitquelle
|
|
750
|
+
// wie das Logo, nur aus einem QR-Modul-Bool statt aus Graustufen gewonnen.
|
|
739
751
|
const breite = gesamtModule * punkte;
|
|
740
|
-
const
|
|
741
|
-
const daten = new Uint8Array(byteJeZeile * breite);
|
|
752
|
+
const bildpunkte = new Uint8Array(breite * breite);
|
|
742
753
|
for (let y = 0; y < breite; y++) {
|
|
743
754
|
const modulY = Math.floor(y / punkte) - ruhezone;
|
|
744
755
|
if (modulY < 0 || modulY >= module)
|
|
@@ -750,18 +761,14 @@ function escPosQrRaster(doc, matrix, options = {}) {
|
|
|
750
761
|
continue;
|
|
751
762
|
if (zeile[modulX] !== true)
|
|
752
763
|
continue;
|
|
753
|
-
|
|
754
|
-
daten[i] = daten[i] | (0x80 >> (x & 7));
|
|
764
|
+
bildpunkte[y * breite + x] = 1;
|
|
755
765
|
}
|
|
756
766
|
}
|
|
767
|
+
const daten = rasterZeilenBytes({ breite, hoehe: breite, punkte: bildpunkte });
|
|
757
768
|
escPosSetStyles(doc, { align: options.align ?? 'center' });
|
|
758
769
|
// GS v 0 m xL xH yL yH d1...dk — m = 0: normale Dichte, 1:1.
|
|
759
|
-
anhaengen(doc,
|
|
760
|
-
|
|
761
|
-
byteJeZeile & 0xff, (byteJeZeile >> 8) & 0xff,
|
|
762
|
-
breite & 0xff, (breite >> 8) & 0xff,
|
|
763
|
-
...daten,
|
|
764
|
-
]);
|
|
770
|
+
anhaengen(doc, rasterBildKopf(breite, breite));
|
|
771
|
+
anhaengen(doc, daten);
|
|
765
772
|
anhaengen(doc, [ZEILENUMBRUCH]);
|
|
766
773
|
if ((options.align ?? 'center') !== 'left') {
|
|
767
774
|
escPosSetStyles(doc, { align: 'left' });
|
|
@@ -777,3 +784,68 @@ function qrRasterPunkte(paperSize, moduleAnzahl, options = {}) {
|
|
|
777
784
|
const deckel = qr_groesse_js_1.QR_MODUL_DECKEL[options.groesse ?? 'auto'];
|
|
778
785
|
return Math.max(1, Math.min(deckel, Math.floor(qr_groesse_js_1.QR_DRUCK_PUNKTE[paperSize] / (moduleAnzahl + 2 * ruhezone))));
|
|
779
786
|
}
|
|
787
|
+
/** Die Rasterzeilen als Bytes: MSB zuerst, jede Zeile auf volle Bytes aufgefuellt. */
|
|
788
|
+
function rasterZeilenBytes(bild) {
|
|
789
|
+
if (!istGanzzahl(bild.breite) || bild.breite < 1 || !istGanzzahl(bild.hoehe) || bild.hoehe < 1) {
|
|
790
|
+
throw new Error('Rasterbild ohne gueltiges Mass');
|
|
791
|
+
}
|
|
792
|
+
if (bild.punkte.length !== bild.breite * bild.hoehe)
|
|
793
|
+
throw new Error('Rasterbild: Punkte passen nicht zum Mass');
|
|
794
|
+
const byteJeZeile = Math.ceil(bild.breite / 8);
|
|
795
|
+
const daten = new Uint8Array(byteJeZeile * bild.hoehe);
|
|
796
|
+
for (let y = 0; y < bild.hoehe; y++) {
|
|
797
|
+
for (let x = 0; x < bild.breite; x++) {
|
|
798
|
+
if (bild.punkte[y * bild.breite + x] !== 1)
|
|
799
|
+
continue;
|
|
800
|
+
const i = y * byteJeZeile + (x >> 3);
|
|
801
|
+
daten[i] = daten[i] | (0x80 >> (x & 7));
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
return daten;
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* Die Rasterzeilen als Base64 -- ohne Buffer, laeuft im Browser und in Node.
|
|
808
|
+
* Eine Stelle fuer ePOS-`<image>` und den Druckjob an den Server.
|
|
809
|
+
*/
|
|
810
|
+
function rasterZeilenBase64(bild) {
|
|
811
|
+
const bytes = rasterZeilenBytes(bild);
|
|
812
|
+
let binaer = '';
|
|
813
|
+
for (let i = 0; i < bytes.length; i += 0x8000) {
|
|
814
|
+
binaer += String.fromCharCode(...bytes.subarray(i, i + 0x8000));
|
|
815
|
+
}
|
|
816
|
+
return btoa(binaer);
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
* Der `GS v 0`-Kopf (Byte-Breite, Zeilenhoehe) -- die Rasterzeilen selbst
|
|
820
|
+
* haengt der Aufrufer an. Gemeinsame Rahmung fuer das Logo (`escPosRasterBild`)
|
|
821
|
+
* und den QR-Bildweg (`escPosQrRaster`): beide drucken dasselbe Bildkommando,
|
|
822
|
+
* nur mit unterschiedlichem Nachlauf (Zeilenvorschub ja/nein).
|
|
823
|
+
*/
|
|
824
|
+
function rasterBildKopf(breite, hoehe) {
|
|
825
|
+
const byteJeZeile = Math.ceil(breite / 8);
|
|
826
|
+
return [GS, 0x76, 0x30, 0x00, byteJeZeile & 0xff, (byteJeZeile >> 8) & 0xff, hoehe & 0xff, (hoehe >> 8) & 0xff];
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* Ein Rasterbild (`GS v 0`) -- das Firmenlogo am Bon.
|
|
830
|
+
*
|
|
831
|
+
* Anders als `escPosQrRaster` folgt KEIN Zeilenvorschub: `GS v 0` schiebt das
|
|
832
|
+
* Papier um die Bildhoehe, ein LF danach waere eine zusaetzliche Leerzeile,
|
|
833
|
+
* die Bildschirm und PDF nicht haben. Die Luft um das Logo kommt aus dem Blatt.
|
|
834
|
+
*/
|
|
835
|
+
function escPosRasterBild(doc, bild, options = {}) {
|
|
836
|
+
// Masse pruefen, BEVOR gepackt wird: ein zu breites Bild soll nicht erst
|
|
837
|
+
// Speicher fuer seine Rasterzeilen belegen. `GS v 0` traegt die Hoehe in zwei
|
|
838
|
+
// Bytes (yL yH) -- ueber 65535 Punkte liefe sie still ueber und der Drucker
|
|
839
|
+
// laese den Rest des Bilds als Befehle.
|
|
840
|
+
if (bild.breite > qr_groesse_js_1.QR_DRUCK_PUNKTE[doc.paperSize])
|
|
841
|
+
throw new Error('Rasterbild breiter als der Druckkopf');
|
|
842
|
+
if (bild.hoehe > 0xffff)
|
|
843
|
+
throw new Error('Rasterbild hoeher als 65535 Punkte');
|
|
844
|
+
const daten = rasterZeilenBytes(bild);
|
|
845
|
+
escPosSetStyles(doc, { align: options.align ?? 'center' });
|
|
846
|
+
anhaengen(doc, rasterBildKopf(bild.breite, bild.hoehe));
|
|
847
|
+
anhaengen(doc, daten);
|
|
848
|
+
if ((options.align ?? 'center') !== 'left') {
|
|
849
|
+
escPosSetStyles(doc, { align: 'left' });
|
|
850
|
+
}
|
|
851
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { type PosPaperSize, type PosAlign, type PosFont, type PosCutMode, type PosCodeTable, type PosTextSize, type QrSize, type QrCorrection, type QrMatrix, type PosStyles, type PosColumn, type EscPosOptions, type EscPosTextOptions, type EscPosHrOptions, type EscPosQrOptions, type EscPosQrRasterOptions, type EscPosDocument, createEscPosDocument, escPosBytes, escPosReset, escPosSetGlobalCodeTable, escPosSetGlobalFont, escPosSetStyles, escPosText, escPosEmptyLines, escPosFeed, escPosCut, escPosHr, escPosRow, escPosQrCode, escPosQrRaster, qrRasterPunkte, encodeEscPosText, qrCodeBytes, escPosMaxCharsPerLine, escPosWortzeilen, wortzeilenText, } from './escpos.js';
|
|
2
|
-
export { type QrModulGroesse, type QrGroesse, QR_MODUL_DECKEL, QR_RUHEZONE_MODULE, QR_MINDEST_PUNKTE, QR_AUSNAHME_PUNKTE, QR_HOECHST_PUNKTE, QR_DRUCK_PUNKTE, qrModulAnzahl, qrGroesseBerechnen, qrGroesseFuer, } from './qr-groesse.js';
|
|
1
|
+
export { type PosPaperSize, type PosAlign, type PosFont, type PosCutMode, type PosCodeTable, type PosTextSize, type QrSize, type QrCorrection, type QrMatrix, type PosStyles, type PosColumn, type EscPosOptions, type EscPosTextOptions, type EscPosHrOptions, type EscPosQrOptions, type EscPosQrRasterOptions, type EscPosDocument, createEscPosDocument, escPosBytes, escPosReset, escPosSetGlobalCodeTable, escPosSetGlobalFont, escPosSetStyles, escPosText, escPosEmptyLines, escPosFeed, escPosCut, escPosHr, escPosRow, escPosQrCode, escPosQrRaster, qrRasterPunkte, type RasterBild, rasterZeilenBytes, rasterZeilenBase64, escPosRasterBild, encodeEscPosText, qrCodeBytes, escPosMaxCharsPerLine, escPosWortzeilen, wortzeilenText, } from './escpos.js';
|
|
2
|
+
export { type QrModulGroesse, type QrGroesse, QR_MODUL_DECKEL, QR_RUHEZONE_MODULE, QR_MINDEST_PUNKTE, QR_AUSNAHME_PUNKTE, QR_HOECHST_PUNKTE, QR_DRUCK_PUNKTE, qrModulAnzahl, qrPasstInVersion, qrGroesseBerechnen, qrGroesseFuer, } from './qr-groesse.js';
|
|
3
3
|
export { escPosPrintableText } from './printable.js';
|
|
4
4
|
export { type UsbEndpointLike, type UsbAlternateLike, type UsbInterfaceLike, type UsbConfigurationLike, type UsbTransferOutResultLike, type UsbWriterLike, type UsbIdentityLike, type UsbDeviceLike, type UsbPrinterEndpoint, type UsbPrinterConnection, USB_VENDOR_EPSON, USB_CLASS_PRINTER, UsbTimeoutError, usbDeviceKey, usbFindPrinterEndpoint, usbWriteAll, usbConnectPrinter, usbPrint, usbDisconnect, } from './webusb.js';
|