@kreiseck/kasseneck-api 0.13.2 → 0.14.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 +70 -0
- package/README.md +31 -5
- 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/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/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 +1 -1
- package/package.json +1 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { ReceiptLayout } from './layout.js';
|
|
2
2
|
import type { PosPaperSize } from '../printing/escpos.js';
|
|
3
|
-
import { type QrModulGroesse } from '../printing/index.js';
|
|
3
|
+
import { type QrModulGroesse, type RasterBild } from '../printing/index.js';
|
|
4
|
+
import { type DruckLogo } from './layout-escpos.js';
|
|
4
5
|
/**
|
|
5
6
|
* ePOS-Print XML (Epson TM-Drucker: Server Direct Print, ePOS-Print ueber
|
|
6
7
|
* HTTP) -- **aus dem Zeichenraster**: jede Rasterzeile wird eine <text>-Zeile
|
|
7
|
-
* mit exakt N Zeichen und Zeilenumbruch, Aufdrucke
|
|
8
|
-
*
|
|
8
|
+
* mit exakt N Zeichen und Zeilenumbruch, Aufdrucke als Rahmen aus
|
|
9
|
+
* Rasterzeilen, QR als <symbol>, Leerraum als <feed>, am Ende Schnitt. Kein
|
|
9
10
|
* eigenes Setzen -- was Bildschirm, ESC/POS und PDF zeigen, druckt der Epson
|
|
10
11
|
* Zeile fuer Zeile genauso.
|
|
11
12
|
*
|
|
@@ -22,16 +23,20 @@ export interface EposPrintXmlOptions {
|
|
|
22
23
|
*/
|
|
23
24
|
qrBreite?: number;
|
|
24
25
|
/**
|
|
25
|
-
* Deckel fuer die gerechnete QR-Modulgroesse; Vorgabe `
|
|
26
|
+
* Deckel fuer die gerechnete QR-Modulgroesse; Vorgabe `auto` (hoechstens 6
|
|
27
|
+
* Punkte je Modul) -- wie ESC/POS, Blatt und der Flutter-Zwilling.
|
|
26
28
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* damit ohne Wahl kein Byte anders herauskommt.
|
|
29
|
+
* Bis 0.13 stand hier `mittel`, weil `auto` damals beim ESC/POS-Wert 4
|
|
30
|
+
* deckelte und dieser Weg seit jeher mit 6 druckt. Seit `auto` ueberall 6
|
|
31
|
+
* heisst, ist das derselbe Wert: ohne Wahl kommt kein Byte anders heraus.
|
|
31
32
|
*/
|
|
32
33
|
qrGroesse?: QrModulGroesse;
|
|
33
34
|
/** Papierschnitt am Ende, Vorgabe true. */
|
|
34
35
|
cut?: boolean;
|
|
36
|
+
/** Firmenlogo; ohne Angabe kein Logo. */
|
|
37
|
+
logo?: DruckLogo | null;
|
|
38
|
+
/** "erstellt mit Kasseneck" am Ende. */
|
|
39
|
+
marke?: boolean;
|
|
35
40
|
}
|
|
36
41
|
/**
|
|
37
42
|
* Das XML **samt** dem, was dem QR unterwegs zugestossen ist -- dieselbe
|
|
@@ -45,6 +50,8 @@ export interface EposPrintErgebnis {
|
|
|
45
50
|
qrAusweich: string | null;
|
|
46
51
|
}
|
|
47
52
|
export declare function eposXmlEscape(text: string): string;
|
|
53
|
+
/** Ein Rasterbild als ePOS-`<image>` (einfarbig, Punktmass, Rasterzeilen Base64). */
|
|
54
|
+
export declare function eposBildXml(bild: RasterBild): string;
|
|
48
55
|
/** Nur das XML; wer die QR-Meldungen braucht, nimmt [eposPrintXmlErgebnis]. */
|
|
49
56
|
export declare function eposPrintXml(layout: ReceiptLayout, options?: EposPrintXmlOptions): string;
|
|
50
57
|
/**
|
|
@@ -77,6 +84,10 @@ export interface EposDirectOptions {
|
|
|
77
84
|
qrBreite?: number;
|
|
78
85
|
/** Deckel fuer die gerechnete QR-Modulgroesse; siehe [EposPrintXmlOptions.qrGroesse]. */
|
|
79
86
|
qrGroesse?: QrModulGroesse;
|
|
87
|
+
/** Firmenlogo; ohne Angabe kein Logo. */
|
|
88
|
+
logo?: DruckLogo | null;
|
|
89
|
+
/** "erstellt mit Kasseneck" am Ende. */
|
|
90
|
+
marke?: boolean;
|
|
80
91
|
timeoutMs?: number;
|
|
81
92
|
}
|
|
82
93
|
export interface EposResponse {
|
package/dist/esm/receipt/epos.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import { QR_DRUCK_PUNKTE, QR_MINDEST_PUNKTE, QR_MODUL_DECKEL, qrGroesseFuer, } from '../printing/index.js';
|
|
2
|
-
import {
|
|
1
|
+
import { QR_DRUCK_PUNKTE, QR_MINDEST_PUNKTE, QR_MODUL_DECKEL, qrGroesseFuer, qrPasstInVersion, rasterZeilenBase64, } from '../printing/index.js';
|
|
2
|
+
import { ZEICHEN_JE_PAPIER } from './grid.js';
|
|
3
|
+
import { blattFuerDruck } from './layout-escpos.js';
|
|
3
4
|
export function eposXmlEscape(text) {
|
|
4
5
|
return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
|
|
5
6
|
}
|
|
7
|
+
/** Ein Rasterbild als ePOS-`<image>` (einfarbig, Punktmass, Rasterzeilen Base64). */
|
|
8
|
+
export function eposBildXml(bild) {
|
|
9
|
+
return `<image width="${bild.breite}" height="${bild.hoehe}" color="color_1" mode="mono">${rasterZeilenBase64(bild)}</image>`;
|
|
10
|
+
}
|
|
6
11
|
const NS = 'http://www.epson-pos.com/schemas/2011/03/epos-print';
|
|
7
12
|
/** Nur das XML; wer die QR-Meldungen braucht, nimmt [eposPrintXmlErgebnis]. */
|
|
8
13
|
export function eposPrintXml(layout, options = {}) {
|
|
@@ -19,8 +24,9 @@ export function eposPrintXml(layout, options = {}) {
|
|
|
19
24
|
* laesst es weg; genau daran fehlte am echten Beleg der QR.
|
|
20
25
|
*/
|
|
21
26
|
export function eposPrintXmlErgebnis(layout, options = {}) {
|
|
22
|
-
const
|
|
23
|
-
const deckel = options.qrGroesse ?? '
|
|
27
|
+
const zeichen = options.zeichen ?? ZEICHEN_JE_PAPIER[layout.paperSize];
|
|
28
|
+
const deckel = options.qrGroesse ?? 'auto';
|
|
29
|
+
const blatt = blattFuerDruck(layout, { zeichen, logo: options.logo, marke: options.marke, qrGroesse: deckel });
|
|
24
30
|
const fest = options.qrBreite === undefined
|
|
25
31
|
? null
|
|
26
32
|
: Math.min(16, Math.max(3, Math.floor(options.qrBreite)));
|
|
@@ -39,6 +45,12 @@ export function eposPrintXmlErgebnis(layout, options = {}) {
|
|
|
39
45
|
return fest;
|
|
40
46
|
if (nutzlast === '')
|
|
41
47
|
return QR_MODUL_DECKEL[deckel];
|
|
48
|
+
// Passt der Inhalt in keine QR-Version, gibt es kein Symbol, das der
|
|
49
|
+
// Drucker setzen koennte -- wie beim Blatt (Anteil 0) geht der Beleg ohne QR.
|
|
50
|
+
if (!qrPasstInVersion(nutzlast)) {
|
|
51
|
+
qrFehler = 'QR-Inhalt passt in keine QR-Version -- Beleg ohne QR';
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
42
54
|
const mass = qrGroesseFuer({
|
|
43
55
|
nutzlast,
|
|
44
56
|
papierbreitePunkte: QR_DRUCK_PUNKTE[layout.paperSize],
|
|
@@ -63,32 +75,34 @@ export function eposPrintXmlErgebnis(layout, options = {}) {
|
|
|
63
75
|
out.push('<text font="font_a"/>');
|
|
64
76
|
out.push('<text align="left"/>');
|
|
65
77
|
out.push('<text width="1" height="1" reverse="false" em="false"/>');
|
|
66
|
-
for (const
|
|
67
|
-
switch (
|
|
68
|
-
case '
|
|
69
|
-
|
|
78
|
+
for (const block of blatt.bloecke) {
|
|
79
|
+
switch (block.art) {
|
|
80
|
+
case 'zeile':
|
|
81
|
+
if (block.leer)
|
|
82
|
+
out.push('<feed line="1"/>');
|
|
83
|
+
else if (block.fett) {
|
|
84
|
+
out.push(`<text em="true">${eposXmlEscape(block.text)} </text>`);
|
|
85
|
+
out.push('<text em="false"/>');
|
|
86
|
+
}
|
|
87
|
+
else
|
|
88
|
+
out.push(`<text>${eposXmlEscape(block.text)} </text>`);
|
|
89
|
+
break;
|
|
90
|
+
case 'logo':
|
|
91
|
+
if (options.logo) {
|
|
92
|
+
out.push('<text align="center"/>');
|
|
93
|
+
out.push(eposBildXml(options.logo.raster));
|
|
94
|
+
out.push('<text align="left"/>');
|
|
95
|
+
}
|
|
70
96
|
break;
|
|
71
97
|
case 'qr': {
|
|
72
|
-
const breite = qrBreiteFuer(
|
|
98
|
+
const breite = qrBreiteFuer(block.nutzlast);
|
|
73
99
|
if (breite === null)
|
|
74
100
|
break;
|
|
75
101
|
out.push('<text align="center"/>');
|
|
76
|
-
out.push(`<symbol type="qrcode_model_2" level="level_m" width="${breite}" height="0" size="0">${eposXmlEscape(
|
|
102
|
+
out.push(`<symbol type="qrcode_model_2" level="level_m" width="${breite}" height="0" size="0">${eposXmlEscape(block.nutzlast)}</symbol>`);
|
|
77
103
|
out.push('<text align="left"/>');
|
|
78
104
|
break;
|
|
79
105
|
}
|
|
80
|
-
case 'banner':
|
|
81
|
-
out.push(`<text width="1" height="2" reverse="${z.ton === 'warnung' ? 'true' : 'false'}" em="true">${eposXmlEscape(z.text)} </text>`);
|
|
82
|
-
out.push('<text width="1" height="1" reverse="false" em="false"/>');
|
|
83
|
-
break;
|
|
84
|
-
default:
|
|
85
|
-
if (z.bold)
|
|
86
|
-
out.push(`<text em="true">${eposXmlEscape(z.text)} </text>`);
|
|
87
|
-
else
|
|
88
|
-
out.push(`<text>${eposXmlEscape(z.text)} </text>`);
|
|
89
|
-
if (z.bold)
|
|
90
|
-
out.push('<text em="false"/>');
|
|
91
|
-
break;
|
|
92
106
|
}
|
|
93
107
|
}
|
|
94
108
|
if (options.cut !== false) {
|
|
@@ -208,6 +222,10 @@ export function eposDirectPrint(layout, o, fetchFn = fetch) {
|
|
|
208
222
|
xmlOptionen.qrBreite = o.qrBreite;
|
|
209
223
|
if (o.qrGroesse !== undefined)
|
|
210
224
|
xmlOptionen.qrGroesse = o.qrGroesse;
|
|
225
|
+
if (o.logo)
|
|
226
|
+
xmlOptionen.logo = o.logo;
|
|
227
|
+
if (o.marke !== undefined)
|
|
228
|
+
xmlOptionen.marke = o.marke;
|
|
211
229
|
return eposDirectSend(eposPrintXml({ ...layout, paperSize: papier }, xmlOptionen), o, fetchFn);
|
|
212
230
|
}
|
|
213
231
|
/** Verbindungstest: leeres Dokument, druckt nichts, liefert den Druckerstatus. */
|
|
@@ -27,7 +27,7 @@ export interface GridLine {
|
|
|
27
27
|
text: string;
|
|
28
28
|
kind: GridLineKind;
|
|
29
29
|
bold: boolean;
|
|
30
|
-
/** Bei `banner
|
|
30
|
+
/** Bei `banner` (Rahmen- und Textzeilen): `warnung` = Test/Ausfall, `belegart` = Storno, Nullbeleg … */
|
|
31
31
|
ton?: 'belegart' | 'warnung';
|
|
32
32
|
/** Bei `qr`: die Nutzlast. */
|
|
33
33
|
qr?: string;
|
package/dist/esm/receipt/grid.js
CHANGED
|
@@ -61,10 +61,18 @@ export function renderReceiptGrid(layout, options = {}) {
|
|
|
61
61
|
for (const t of wortzeilenText(z.text, zeichen))
|
|
62
62
|
lines.push({ text: ausrichten(t, zeichen, z.align), kind: 'text', bold: z.bold });
|
|
63
63
|
break;
|
|
64
|
-
case 'banner':
|
|
64
|
+
case 'banner': {
|
|
65
|
+
// Der Rahmen ist Teil des Rasters: eine Zeile '=' ueber die volle Breite
|
|
66
|
+
// davor und danach. So setzt ihn jeder Weg -- Bildschirm, Bon, ePOS, PDF,
|
|
67
|
+
// myPOS -- Zeichen fuer Zeichen gleich. Vorher zeichnete jeder Weg seinen
|
|
68
|
+
// eigenen Rahmen (Rechteck, doppelt hoch, invers, gefuellt).
|
|
69
|
+
const rahmen = '='.repeat(zeichen);
|
|
70
|
+
lines.push({ text: rahmen, kind: 'banner', bold: true, ton: z.ton });
|
|
65
71
|
for (const t of wortzeilenText(z.text, zeichen))
|
|
66
72
|
lines.push({ text: ausrichten(t, zeichen, 'center'), kind: 'banner', bold: true, ton: z.ton });
|
|
73
|
+
lines.push({ text: rahmen, kind: 'banner', bold: true, ton: z.ton });
|
|
67
74
|
break;
|
|
75
|
+
}
|
|
68
76
|
case 'rule':
|
|
69
77
|
lines.push({ text: (z.char || '-').charAt(0).repeat(zeichen), kind: 'rule', bold: false });
|
|
70
78
|
break;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { type LayoutAlign, type LayoutColumn, type LayoutTextLine, type LayoutColumnsLine, type LayoutRuleLine, type LayoutSpaceLine, type LayoutQrLine, type LayoutLine, type ReceiptLayout, type BuildReceiptLayoutOptions, buildReceiptLayout, receiptSignatureFailed, receiptSignatureIsTest, receiptIsZero, receiptAmountsAreZero, receiptIsSmallBusinessConsistent, receiptZdaText, type Pruefangaben, AKTUELLES_REGELWERK, type LayoutBannerLine, type LayoutRegelwerk, SMALL_BUSINESS_NOTICE, formatCents, } from './layout.js';
|
|
2
|
-
export { type EscPosLayoutOptions, type EscPosLayoutErgebnis, type QrPrintMode, escPosLayoutBytes, escPosLayoutErgebnis, } from './layout-escpos.js';
|
|
2
|
+
export { type EscPosLayoutOptions, type EscPosLayoutErgebnis, type QrPrintMode, type DruckLogo, pruefeLogoRaster, escPosLayoutBytes, escPosLayoutErgebnis, } from './layout-escpos.js';
|
|
3
3
|
export { type GridLine, type GridLineKind, type ReceiptGrid, type RenderReceiptGridOptions, renderReceiptGrid, gridSpaltenBreiten, gridAlsText, ZEICHEN_JE_PAPIER, } from './grid.js';
|
|
4
|
-
export { type EposPrintXmlOptions, type EposPrintErgebnis, type EposDirectOptions, type EposResponse, EposConnectionError, eposPrintXml, eposPrintXmlErgebnis, eposXmlEscape, eposServiceUrl, eposSoapEnvelope, eposParseResponse, eposDirectPrint, eposDirectStatus } from './epos.js';
|
|
4
|
+
export { type EposPrintXmlOptions, type EposPrintErgebnis, type EposDirectOptions, type EposResponse, EposConnectionError, eposPrintXml, eposPrintXmlErgebnis, eposXmlEscape, eposBildXml, eposServiceUrl, eposSoapEnvelope, eposParseResponse, eposDirectPrint, eposDirectStatus } from './epos.js';
|
|
5
|
+
export { type LogoStufe, type BlattLogo, type LogoMass, type BlattBlock, type BelegBlatt, type BelegBlattOptionen, LOGO_STUFEN, LOGO_PIXEL_MAX, PUNKTE_JE_ZEICHEN, PUNKTE_JE_ZEILE, MARKE_TEXT, papierFuerZeichen, logoMass, logoPixelZulaessig, logoRasterMass, qrBlattAnteil, belegBlatt, } from './blatt.js';
|
|
6
|
+
export { logoRaster } from './bild.js';
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { buildReceiptLayout, receiptSignatureFailed, receiptSignatureIsTest, receiptIsZero, receiptAmountsAreZero, receiptIsSmallBusinessConsistent, receiptZdaText, AKTUELLES_REGELWERK, SMALL_BUSINESS_NOTICE, formatCents, } from './layout.js';
|
|
2
|
-
export { escPosLayoutBytes, escPosLayoutErgebnis, } from './layout-escpos.js';
|
|
2
|
+
export { pruefeLogoRaster, escPosLayoutBytes, escPosLayoutErgebnis, } from './layout-escpos.js';
|
|
3
3
|
export { renderReceiptGrid, gridSpaltenBreiten, gridAlsText, ZEICHEN_JE_PAPIER, } from './grid.js';
|
|
4
|
-
export { EposConnectionError, eposPrintXml, eposPrintXmlErgebnis, eposXmlEscape, eposServiceUrl, eposSoapEnvelope, eposParseResponse, eposDirectPrint, eposDirectStatus } from './epos.js';
|
|
4
|
+
export { EposConnectionError, eposPrintXml, eposPrintXmlErgebnis, eposXmlEscape, eposBildXml, eposServiceUrl, eposSoapEnvelope, eposParseResponse, eposDirectPrint, eposDirectStatus } from './epos.js';
|
|
5
|
+
export { LOGO_STUFEN, LOGO_PIXEL_MAX, PUNKTE_JE_ZEICHEN, PUNKTE_JE_ZEILE, MARKE_TEXT, papierFuerZeichen, logoMass, logoPixelZulaessig, logoRasterMass, qrBlattAnteil, belegBlatt, } from './blatt.js';
|
|
6
|
+
export { logoRaster } from './bild.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { type PosCodeTable, type PosCutMode, type PosPaperSize, type QrCorrection, type QrMatrix, type QrModulGroesse, type QrSize } from '../printing/index.js';
|
|
1
|
+
import { type PosCodeTable, type PosCutMode, type PosPaperSize, type QrCorrection, type QrMatrix, type QrModulGroesse, type QrSize, type RasterBild } from '../printing/index.js';
|
|
2
2
|
import type { ReceiptLayout } from './layout.js';
|
|
3
|
+
import { type BelegBlatt, type LogoStufe, type LogoMass } from './blatt.js';
|
|
3
4
|
/**
|
|
4
5
|
* Bruecke vom Layout-Modell zu ESC/POS-Bytes — der Bondrucker-Ausgabeweg.
|
|
5
6
|
*
|
|
@@ -28,6 +29,29 @@ import type { ReceiptLayout } from './layout.js';
|
|
|
28
29
|
* (`qrMatrix`), weil dieses Paket keine QR-Codes rechnet.
|
|
29
30
|
*/
|
|
30
31
|
export type QrPrintMode = 'native' | 'nativeModel1' | 'imageRaster';
|
|
32
|
+
/** Firmenlogo fuer den Druck: Stufe, Pixelmass des Originals und das fertige Rasterbild (`logoRaster`). */
|
|
33
|
+
export interface DruckLogo {
|
|
34
|
+
stufe: LogoStufe;
|
|
35
|
+
pxBreite: number;
|
|
36
|
+
pxHoehe: number;
|
|
37
|
+
raster: RasterBild;
|
|
38
|
+
}
|
|
39
|
+
/** Das Rasterbild muss genau so gross sein, wie das Blatt das Logo setzt -- sonst stuende am Bon ein anderes Logo als am Schirm. */
|
|
40
|
+
export declare function pruefeLogoRaster(logo: DruckLogo, mass: LogoMass, zeichen: number): void;
|
|
41
|
+
/**
|
|
42
|
+
* Baut das Blatt fuer einen Druckweg (ESC/POS, ePOS) an EINER Stelle: die
|
|
43
|
+
* Zuordnung `DruckLogo` -> `BlattLogo` und die Groessenpruefung des mitgebrachten
|
|
44
|
+
* Rasterbilds teilen sich beide Wege -- ohne das muesste eine Aenderung daran an
|
|
45
|
+
* zwei Stellen nachgezogen werden. Wirft VOR jeder Ausgabe (also bevor der
|
|
46
|
+
* Aufrufer auch nur ein Byte/Zeichen geschrieben hat), wenn das Rasterbild nicht
|
|
47
|
+
* zur Logo-Stufe passt.
|
|
48
|
+
*/
|
|
49
|
+
export declare function blattFuerDruck(layout: ReceiptLayout, optionen: {
|
|
50
|
+
zeichen: number;
|
|
51
|
+
logo?: DruckLogo | null;
|
|
52
|
+
marke?: boolean;
|
|
53
|
+
qrGroesse: QrModulGroesse;
|
|
54
|
+
}): BelegBlatt;
|
|
31
55
|
export interface EscPosLayoutOptions {
|
|
32
56
|
/** Papierbreite; Vorgabe ist die des Layouts (dessen Spaltenbreiten daran haengen). */
|
|
33
57
|
paperSize?: PosPaperSize;
|
|
@@ -40,9 +64,9 @@ export interface EscPosLayoutOptions {
|
|
|
40
64
|
* dann passt der Aufrufer selbst auf, dass das Symbol aufs Papier geht.
|
|
41
65
|
*/
|
|
42
66
|
qrSize?: QrSize;
|
|
43
|
-
/** Fehlerkorrekturstufe des QR-Codes. */
|
|
67
|
+
/** Fehlerkorrekturstufe des QR-Codes; Vorgabe `M` (wie ePOS, Bildweg und Blatt). */
|
|
44
68
|
qrCorrection?: QrCorrection;
|
|
45
|
-
/** Deckel fuer die gerechnete Modulgroesse; Vorgabe `auto
|
|
69
|
+
/** Deckel fuer die gerechnete Modulgroesse; Vorgabe `auto` (hoechstens 6 Punkte je Modul). */
|
|
46
70
|
qrGroesse?: QrModulGroesse;
|
|
47
71
|
/** Druckweg des QR; Vorgabe `native` (der Bestandsweg). */
|
|
48
72
|
qrModus?: QrPrintMode;
|
|
@@ -54,6 +78,10 @@ export interface EscPosLayoutOptions {
|
|
|
54
78
|
* aus der QR-Bibliothek, die er ohnehin fuer den Bildschirm benutzt.
|
|
55
79
|
*/
|
|
56
80
|
qrMatrix?: (nutzlast: string) => QrMatrix;
|
|
81
|
+
/** Firmenlogo; ohne Angabe kein Logo (Bestand). */
|
|
82
|
+
logo?: DruckLogo | null;
|
|
83
|
+
/** "erstellt mit Kasseneck" am Ende (Konto-Flag `kreiseck_logo`). */
|
|
84
|
+
marke?: boolean;
|
|
57
85
|
}
|
|
58
86
|
/**
|
|
59
87
|
* Der Bytestrom **samt** dem, was dem QR unterwegs zugestossen ist.
|
|
@@ -1,5 +1,35 @@
|
|
|
1
|
-
import { createEscPosDocument, escPosBytes, escPosCut, escPosFeed, escPosPrintableText, escPosQrCode, escPosQrRaster, escPosReset, escPosText, QR_DRUCK_PUNKTE, qrGroesseFuer, } from '../printing/index.js';
|
|
2
|
-
import {
|
|
1
|
+
import { createEscPosDocument, escPosBytes, escPosCut, escPosFeed, escPosPrintableText, escPosQrCode, escPosQrRaster, escPosRasterBild, escPosReset, escPosText, QR_DRUCK_PUNKTE, qrGroesseFuer, qrPasstInVersion, } from '../printing/index.js';
|
|
2
|
+
import { belegBlatt, logoRasterMass } from './blatt.js';
|
|
3
|
+
import { ZEICHEN_JE_PAPIER } from './grid.js';
|
|
4
|
+
/** Das Rasterbild muss genau so gross sein, wie das Blatt das Logo setzt -- sonst stuende am Bon ein anderes Logo als am Schirm. */
|
|
5
|
+
export function pruefeLogoRaster(logo, mass, zeichen) {
|
|
6
|
+
const soll = logoRasterMass(mass, zeichen);
|
|
7
|
+
if (logo.raster.breite !== soll.breite || logo.raster.hoehe !== soll.hoehe) {
|
|
8
|
+
throw new Error(`Logo-Raster ${logo.raster.breite}x${logo.raster.hoehe} passt nicht zum Blatt (${soll.breite}x${soll.hoehe})`);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Baut das Blatt fuer einen Druckweg (ESC/POS, ePOS) an EINER Stelle: die
|
|
13
|
+
* Zuordnung `DruckLogo` -> `BlattLogo` und die Groessenpruefung des mitgebrachten
|
|
14
|
+
* Rasterbilds teilen sich beide Wege -- ohne das muesste eine Aenderung daran an
|
|
15
|
+
* zwei Stellen nachgezogen werden. Wirft VOR jeder Ausgabe (also bevor der
|
|
16
|
+
* Aufrufer auch nur ein Byte/Zeichen geschrieben hat), wenn das Rasterbild nicht
|
|
17
|
+
* zur Logo-Stufe passt.
|
|
18
|
+
*/
|
|
19
|
+
export function blattFuerDruck(layout, optionen) {
|
|
20
|
+
const blattOptionen = {
|
|
21
|
+
zeichen: optionen.zeichen,
|
|
22
|
+
marke: optionen.marke === true,
|
|
23
|
+
qrGroesse: optionen.qrGroesse,
|
|
24
|
+
};
|
|
25
|
+
if (optionen.logo)
|
|
26
|
+
blattOptionen.logo = { stufe: optionen.logo.stufe, pxBreite: optionen.logo.pxBreite, pxHoehe: optionen.logo.pxHoehe };
|
|
27
|
+
const blatt = belegBlatt(layout, blattOptionen);
|
|
28
|
+
const logoBlock = blatt.bloecke.find((b) => b.art === 'logo');
|
|
29
|
+
if (optionen.logo && logoBlock && logoBlock.art === 'logo')
|
|
30
|
+
pruefeLogoRaster(optionen.logo, logoBlock, blatt.zeichen);
|
|
31
|
+
return blatt;
|
|
32
|
+
}
|
|
3
33
|
/**
|
|
4
34
|
* Druckbar gemachtes Layout: Texte durch [escPosPrintableText] (Codepage,
|
|
5
35
|
* "EUR" statt "€", Striche), damit das Raster mit den Zeichen rechnet, die
|
|
@@ -68,6 +98,13 @@ export function escPosLayoutErgebnis(layout, options = {}) {
|
|
|
68
98
|
* `qrFehler` aus `escPosQrCode`, und der Beleg geht ohne QR hinaus.
|
|
69
99
|
*/
|
|
70
100
|
const qrZeile = (nutzlast) => {
|
|
101
|
+
// Ein Inhalt, der in keine QR-Version passt, laesst sich weder als Befehl
|
|
102
|
+
// noch als Bild drucken -- beide Wege wuerfen. Der Beleg geht ohne QR
|
|
103
|
+
// hinaus und sagt es ueber `qrFehler`, wie das Blatt (Anteil 0).
|
|
104
|
+
if (nutzlast !== '' && !qrPasstInVersion(nutzlast)) {
|
|
105
|
+
doc.qrFehler = 'QR-Inhalt passt in keine QR-Version -- Beleg ohne QR';
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
71
108
|
const raster = options.qrMatrix;
|
|
72
109
|
if (nutzlast !== '' && raster !== undefined) {
|
|
73
110
|
if (modus === 'imageRaster') {
|
|
@@ -94,27 +131,28 @@ export function escPosLayoutErgebnis(layout, options = {}) {
|
|
|
94
131
|
}
|
|
95
132
|
escPosQrCode(doc, nutzlast, qrOptionen);
|
|
96
133
|
};
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
134
|
+
// `blattFuerDruck` prueft das Logo-Raster bereits VOR der Rueckgabe -- die
|
|
135
|
+
// Schleife unten schreibt darum nie ein Byte auf ein falsch grosses Logo.
|
|
136
|
+
const blatt = blattFuerDruck(druckbaresLayout(layout), {
|
|
137
|
+
zeichen: ZEICHEN_JE_PAPIER[paperSize],
|
|
138
|
+
logo: options.logo,
|
|
139
|
+
marke: options.marke,
|
|
140
|
+
qrGroesse: options.qrGroesse ?? 'auto',
|
|
141
|
+
});
|
|
142
|
+
for (const block of blatt.bloecke) {
|
|
143
|
+
switch (block.art) {
|
|
103
144
|
case 'qr':
|
|
104
|
-
qrZeile(
|
|
145
|
+
qrZeile(block.nutzlast);
|
|
105
146
|
break;
|
|
106
|
-
case '
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
// weiss-auf-schwarz und sah damit anders aus als jede Anzeige).
|
|
110
|
-
const rahmen = '='.repeat(ZEICHEN_JE_PAPIER[paperSize]);
|
|
111
|
-
escPosText(doc, rahmen, { styles: { align: 'left', bold: true } });
|
|
112
|
-
escPosText(doc, zeile.text.trimEnd(), { styles: { align: 'left', bold: true, height: 2 } });
|
|
113
|
-
escPosText(doc, rahmen, { styles: { align: 'left', bold: true } });
|
|
147
|
+
case 'logo':
|
|
148
|
+
if (options.logo)
|
|
149
|
+
escPosRasterBild(doc, options.logo.raster, { align: 'center' });
|
|
114
150
|
break;
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
151
|
+
case 'zeile':
|
|
152
|
+
if (block.leer)
|
|
153
|
+
escPosFeed(doc, 1);
|
|
154
|
+
else
|
|
155
|
+
escPosText(doc, block.text.trimEnd(), { styles: { align: 'left', bold: block.fett } });
|
|
118
156
|
break;
|
|
119
157
|
}
|
|
120
158
|
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
{
|
|
2
|
+
"zeichen": 32,
|
|
3
|
+
"bloecke": [
|
|
4
|
+
{
|
|
5
|
+
"art": "logo",
|
|
6
|
+
"breiteAnteil": 0.62,
|
|
7
|
+
"hoeheZeilen": 3.968
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"art": "zeile",
|
|
11
|
+
"text": " ",
|
|
12
|
+
"fett": false,
|
|
13
|
+
"leer": true
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"art": "zeile",
|
|
17
|
+
"text": " Bäckerei Muster ",
|
|
18
|
+
"fett": true,
|
|
19
|
+
"leer": false
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"art": "zeile",
|
|
23
|
+
"text": " Hauptplatz 1 ",
|
|
24
|
+
"fett": false,
|
|
25
|
+
"leer": false
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"art": "zeile",
|
|
29
|
+
"text": " 4830 Hallstatt ",
|
|
30
|
+
"fett": false,
|
|
31
|
+
"leer": false
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"art": "zeile",
|
|
35
|
+
"text": " ATU12345678 ",
|
|
36
|
+
"fett": false,
|
|
37
|
+
"leer": false
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"art": "zeile",
|
|
41
|
+
"text": " +43 6134 12345 ",
|
|
42
|
+
"fett": false,
|
|
43
|
+
"leer": false
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"art": "zeile",
|
|
47
|
+
"text": " ",
|
|
48
|
+
"fett": false,
|
|
49
|
+
"leer": true
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"art": "zeile",
|
|
53
|
+
"text": "Datum: 13.08.2026 10:15:30",
|
|
54
|
+
"fett": false,
|
|
55
|
+
"leer": false
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"art": "zeile",
|
|
59
|
+
"text": "Kassen-ID: KASSE1",
|
|
60
|
+
"fett": false,
|
|
61
|
+
"leer": false
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"art": "zeile",
|
|
65
|
+
"text": "Beleg-ID: AT0-KASSE1-66",
|
|
66
|
+
"fett": false,
|
|
67
|
+
"leer": false
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"art": "zeile",
|
|
71
|
+
"text": " ",
|
|
72
|
+
"fett": false,
|
|
73
|
+
"leer": true
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"art": "zeile",
|
|
77
|
+
"text": "1 x Behandlung 120,00 A",
|
|
78
|
+
"fett": false,
|
|
79
|
+
"leer": false
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"art": "zeile",
|
|
83
|
+
"text": " ",
|
|
84
|
+
"fett": false,
|
|
85
|
+
"leer": true
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"art": "zeile",
|
|
89
|
+
"text": "MwSt% MwSt Netto Brutto",
|
|
90
|
+
"fett": false,
|
|
91
|
+
"leer": false
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"art": "zeile",
|
|
95
|
+
"text": "A 20% 20,00 100,00 120,00",
|
|
96
|
+
"fett": false,
|
|
97
|
+
"leer": false
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"art": "zeile",
|
|
101
|
+
"text": "--------------------------------",
|
|
102
|
+
"fett": false,
|
|
103
|
+
"leer": false
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"art": "zeile",
|
|
107
|
+
"text": "Gesamt: 120,00 €",
|
|
108
|
+
"fett": false,
|
|
109
|
+
"leer": false
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"art": "zeile",
|
|
113
|
+
"text": "Zahlungsart: Kartenzahlung",
|
|
114
|
+
"fett": false,
|
|
115
|
+
"leer": false
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"art": "zeile",
|
|
119
|
+
"text": " ",
|
|
120
|
+
"fett": false,
|
|
121
|
+
"leer": true
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"art": "qr",
|
|
125
|
+
"nutzlast": "_R1-AT1_KASSE1_AT0-KASSE1-66_2026-08-13T10:15:30_120,00_0,00_0,00_0,00_0,00_UMSATZ_VORGAENGER_6F0404F0_SIGNATUR",
|
|
126
|
+
"breiteAnteil": 0.828125
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"art": "zeile",
|
|
130
|
+
"text": " ",
|
|
131
|
+
"fett": false,
|
|
132
|
+
"leer": true
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"art": "zeile",
|
|
136
|
+
"text": " Vielen Dank für Ihren Einkauf ",
|
|
137
|
+
"fett": false,
|
|
138
|
+
"leer": false
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"art": "zeile",
|
|
142
|
+
"text": " www.baeckerei-muster.at ",
|
|
143
|
+
"fett": false,
|
|
144
|
+
"leer": false
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"art": "zeile",
|
|
148
|
+
"text": " ",
|
|
149
|
+
"fett": false,
|
|
150
|
+
"leer": true
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"art": "zeile",
|
|
154
|
+
"text": " erstellt mit Kasseneck ",
|
|
155
|
+
"fett": false,
|
|
156
|
+
"leer": false
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
}
|