@kreiseck/kasseneck-api 0.10.0 → 0.11.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.
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QR_DRUCK_PUNKTE = exports.QR_HOECHST_PUNKTE = exports.QR_AUSNAHME_PUNKTE = exports.QR_MINDEST_PUNKTE = exports.QR_RUHEZONE_MODULE = exports.QR_MODUL_DECKEL = void 0;
4
+ exports.qrModulAnzahl = qrModulAnzahl;
5
+ exports.qrGroesseBerechnen = qrGroesseBerechnen;
6
+ exports.qrGroesseFuer = qrGroesseFuer;
7
+ /** Groesste Modulgroesse in Druckpunkten, die der jeweilige Deckel zulaesst. */
8
+ exports.QR_MODUL_DECKEL = {
9
+ auto: 4,
10
+ klein: 4,
11
+ mittel: 6,
12
+ gross: 8,
13
+ };
14
+ // --------------------------------------------------------------- Konstanten
15
+ /** Ruhezone je Seite, in Modulen (QR-Norm). */
16
+ exports.QR_RUHEZONE_MODULE = 4;
17
+ /** Untergrenze: 4 Punkte sind bei 203 dpi rund 0,5 mm je Modul. */
18
+ exports.QR_MINDEST_PUNKTE = 4;
19
+ /** Ausnahme, wenn `QR_MINDEST_PUNKTE` nicht passt — gemeldet, nicht still. */
20
+ exports.QR_AUSNAHME_PUNKTE = 3;
21
+ /** Obergrenze des Druckbefehls in diesem Stack (`GS ( k` Funktion 167: 1..8). */
22
+ exports.QR_HOECHST_PUNKTE = 8;
23
+ /**
24
+ * Druckbreite des Kopfes in Punkten (203 dpi): 58 mm = 384, 80 mm = 576 —
25
+ * Zwilling von `KeckPaperSize.druckPunkte`.
26
+ *
27
+ * Nicht dasselbe wie die Spaltenbreite in `escpos.ts` (372/558): die stammt
28
+ * aus `EscPaperSize.width` und laesst absichtlich Rand fuer die
29
+ * Textpositionierung. Wer rechnet, ob ein Symbol aufs Papier passt, braucht
30
+ * die echte Kopfbreite — ein QR, der auch nur einen Punkt zu breit ist, wird
31
+ * von den meisten Geraeten gar nicht gedruckt.
32
+ */
33
+ exports.QR_DRUCK_PUNKTE = { mm58: 384, mm80: 576 };
34
+ /**
35
+ * Nutzlast in Byte, die eine QR-Version 1..40 bei Fehlerkorrektur **M** im
36
+ * Byte-Modus aufnimmt (ISO/IEC 18004, Tabelle 7).
37
+ *
38
+ * Byte-Modus, weil die RKSV-Nutzlast beliebige Zeichen traegt; Ziffern- oder
39
+ * Alphanumerik-Modus waere enger gefasst und wuerde fuer denselben Text
40
+ * weniger Module ergeben — also zu klein rechnen.
41
+ */
42
+ const BYTE_KAPAZITAET_M = [
43
+ 14, 26, 42, 62, 84, 106, 122, 152, 180, 213,
44
+ 251, 287, 331, 362, 412, 450, 504, 560, 624, 666,
45
+ 711, 779, 857, 911, 997, 1059, 1125, 1190, 1264, 1370,
46
+ 1452, 1538, 1628, 1722, 1809, 1911, 1989, 2099, 2213, 2331,
47
+ ];
48
+ // ------------------------------------------------------------- oeffentlich
49
+ /**
50
+ * Modulanzahl, die `nutzlast` bei Fehlerkorrektur **M** braucht.
51
+ *
52
+ * Warum M, obwohl der native Befehl mit L druckt: M braucht bei gleicher
53
+ * Nutzlast gleich viele oder mehr Module als L. Wer mit M rechnet und mit L
54
+ * druckt, druckt nie breiter als gerechnet — die Rechnung ist konservativ,
55
+ * nie knapp. Umgekehrt waere sie eine Rechnung, die aufgeht, und ein Symbol,
56
+ * das ueber den Papierrand laeuft. Dasselbe gilt fuer die Byte-Zaehlung: hier
57
+ * zaehlt UTF-8 (wie im Flutter-Zwilling), waehrend `qrCodeBytes` die Nutzlast
58
+ * als Latin-1 sendet — UTF-8 ist nie kuerzer, die Rechnung also nie zu klein.
59
+ *
60
+ * Wirft, wenn die Nutzlast in keine Version passt — wie `qrCodeBytes` bei zu
61
+ * langem Inhalt. Ein still zurueckgegebenes "passt nicht" haette den
62
+ * Datenfehler als Papierfehler getarnt.
63
+ */
64
+ function qrModulAnzahl(nutzlast) {
65
+ const laenge = new TextEncoder().encode(nutzlast).length;
66
+ for (let i = 0; i < BYTE_KAPAZITAET_M.length; i++) {
67
+ if (laenge <= BYTE_KAPAZITAET_M[i])
68
+ return 17 + 4 * (i + 1);
69
+ }
70
+ throw new Error('QR-Inhalt ist zu lang');
71
+ }
72
+ /**
73
+ * Groesste Modulgroesse, mit der `moduleAnzahl` Module **samt Ruhezone** in
74
+ * `papierbreitePunkte` passen, gedeckelt durch `groesse`.
75
+ *
76
+ * Wirft bei sinnlosen Eingaben: eine Papierbreite von 0 oder ein Symbol ohne
77
+ * Module ist ein Programmierfehler, und ein still zurueckgegebenes "passt
78
+ * nicht" haette ihn als Druckerproblem getarnt.
79
+ */
80
+ function qrGroesseBerechnen(options) {
81
+ const { papierbreitePunkte, moduleAnzahl } = options;
82
+ const groesse = options.groesse ?? 'auto';
83
+ if (!Number.isInteger(papierbreitePunkte) || papierbreitePunkte <= 0) {
84
+ throw new Error('papierbreitePunkte muss eine Ganzzahl > 0 sein');
85
+ }
86
+ if (!Number.isInteger(moduleAnzahl) || moduleAnzahl <= 0) {
87
+ throw new Error('moduleAnzahl muss eine Ganzzahl > 0 sein');
88
+ }
89
+ const roh = exports.QR_MODUL_DECKEL[groesse];
90
+ if (roh === undefined) {
91
+ throw new Error(`Unbekannte QR-Modulgroesse: ${String(groesse)}`);
92
+ }
93
+ const gesamtModule = moduleAnzahl + exports.QR_RUHEZONE_MODULE * 2;
94
+ const passend = Math.floor(papierbreitePunkte / gesamtModule);
95
+ if (passend < exports.QR_AUSNAHME_PUNKTE) {
96
+ return { punkte: null, module: moduleAnzahl, breitePunkte: 0, unterMindestmass: false, passt: false };
97
+ }
98
+ const deckel = Math.min(Math.max(roh, exports.QR_AUSNAHME_PUNKTE), exports.QR_HOECHST_PUNKTE);
99
+ const punkte = passend < exports.QR_MINDEST_PUNKTE ? exports.QR_AUSNAHME_PUNKTE : Math.min(passend, deckel);
100
+ return {
101
+ punkte: punkte,
102
+ module: moduleAnzahl,
103
+ breitePunkte: gesamtModule * punkte,
104
+ unterMindestmass: punkte < exports.QR_MINDEST_PUNKTE,
105
+ passt: true,
106
+ };
107
+ }
108
+ /**
109
+ * Wie `qrGroesseBerechnen`, nur mit der Modulanzahl aus `nutzlast`.
110
+ *
111
+ * Eine leere Nutzlast ergibt kein Symbol — sie "passt nicht", statt zu
112
+ * werfen: der Aufrufer behandelt den Fall ohnehin schon (leerer QR am Beleg
113
+ * ist ein Datenfehler, kein Papierfehler).
114
+ */
115
+ function qrGroesseFuer(options) {
116
+ if (options.nutzlast === '') {
117
+ return { punkte: null, module: 0, breitePunkte: 0, unterMindestmass: false, passt: false };
118
+ }
119
+ const weiter = {
120
+ papierbreitePunkte: options.papierbreitePunkte,
121
+ moduleAnzahl: qrModulAnzahl(options.nutzlast),
122
+ };
123
+ if (options.groesse !== undefined)
124
+ weiter.groesse = options.groesse;
125
+ return qrGroesseBerechnen(weiter);
126
+ }
@@ -1,5 +1,6 @@
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
4
  /**
4
5
  * ePOS-Print XML (Epson TM-Drucker: Server Direct Print, ePOS-Print ueber
5
6
  * HTTP) -- **aus dem Zeichenraster**: jede Rasterzeile wird eine <text>-Zeile
@@ -14,13 +15,49 @@ import type { PosPaperSize } from '../printing/escpos.js';
14
15
  export interface EposPrintXmlOptions {
15
16
  /** Zeichen je Zeile; Vorgabe nach `layout.paperSize` (32/48). */
16
17
  zeichen?: number;
17
- /** QR-Modulgroesse (Epson `width` 3..16), Vorgabe 6. */
18
+ /**
19
+ * **Feste** QR-Modulgroesse (Epson `width` 3..16). Gesetzt schaltet sie die
20
+ * Rechnung ab -- dann passt der Aufrufer selbst auf, dass das Symbol samt
21
+ * Ruhezone auf die Rolle geht.
22
+ */
18
23
  qrBreite?: number;
24
+ /**
25
+ * Deckel fuer die gerechnete QR-Modulgroesse; Vorgabe `mittel`.
26
+ *
27
+ * Warum `mittel` und nicht `auto`: `auto` deckelt beim Bestandswert des
28
+ * **ESC/POS**-Befehls dieses Pakets (4), dieser Weg druckt aber seit jeher
29
+ * mit 6. Die Vorgabe nennt den Bestandswert dieses Wegs also ausdruecklich,
30
+ * damit ohne Wahl kein Byte anders herauskommt.
31
+ */
32
+ qrGroesse?: QrModulGroesse;
19
33
  /** Papierschnitt am Ende, Vorgabe true. */
20
34
  cut?: boolean;
21
35
  }
36
+ /**
37
+ * Das XML **samt** dem, was dem QR unterwegs zugestossen ist -- dieselbe
38
+ * Buchfuehrung wie `EscPosLayoutErgebnis` am ESC/POS-Weg.
39
+ */
40
+ export interface EposPrintErgebnis {
41
+ xml: string;
42
+ /** Der Beleg ging ohne QR hinaus; das Symbol passt auch mit 3 Punkten nicht. */
43
+ qrFehler: string | null;
44
+ /** Der QR steht da, aber unter der Mindest-Modulgroesse. */
45
+ qrAusweich: string | null;
46
+ }
22
47
  export declare function eposXmlEscape(text: string): string;
48
+ /** Nur das XML; wer die QR-Meldungen braucht, nimmt [eposPrintXmlErgebnis]. */
23
49
  export declare function eposPrintXml(layout: ReceiptLayout, options?: EposPrintXmlOptions): string;
50
+ /**
51
+ * Wie [eposPrintXml], gibt aber zusaetzlich zurueck, was dem QR zugestossen
52
+ * ist.
53
+ *
54
+ * **Die QR-Modulgroesse wird gerechnet.** Vorher stand hier fest 6, unabhaengig
55
+ * von der Papierbreite: ein Beleg-QR mit realer RKSV-Nutzlast hat 57 Module,
56
+ * mit Ruhezone 65, bei sechs Punkten also 390 Druckpunkte -- und ein
57
+ * 58-mm-Kopf hat 384. Der Epson schneidet ein zu breites Symbol nicht ab, er
58
+ * laesst es weg; genau daran fehlte am echten Beleg der QR.
59
+ */
60
+ export declare function eposPrintXmlErgebnis(layout: ReceiptLayout, options?: EposPrintXmlOptions): EposPrintErgebnis;
24
61
  /**
25
62
  * Epson-Drucker mit ePOS-Print direkt aus dem Browser ansprechen (ohne
26
63
  * Server-Umweg): POST an `https://<ip>/cgi-bin/epos/service.cgi`. Der Drucker
@@ -36,6 +73,10 @@ export interface EposDirectOptions {
36
73
  devid?: string;
37
74
  /** Papier des Druckers -- bestimmt das Raster; Vorgabe: das des Layouts. */
38
75
  papier?: PosPaperSize;
76
+ /** Feste QR-Modulgroesse; siehe [EposPrintXmlOptions.qrBreite]. */
77
+ qrBreite?: number;
78
+ /** Deckel fuer die gerechnete QR-Modulgroesse; siehe [EposPrintXmlOptions.qrGroesse]. */
79
+ qrGroesse?: QrModulGroesse;
39
80
  timeoutMs?: number;
40
81
  }
41
82
  export interface EposResponse {
@@ -3,19 +3,71 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EposConnectionError = void 0;
4
4
  exports.eposXmlEscape = eposXmlEscape;
5
5
  exports.eposPrintXml = eposPrintXml;
6
+ exports.eposPrintXmlErgebnis = eposPrintXmlErgebnis;
6
7
  exports.eposServiceUrl = eposServiceUrl;
7
8
  exports.eposSoapEnvelope = eposSoapEnvelope;
8
9
  exports.eposParseResponse = eposParseResponse;
9
10
  exports.eposDirectPrint = eposDirectPrint;
10
11
  exports.eposDirectStatus = eposDirectStatus;
12
+ const index_js_1 = require("../printing/index.js");
11
13
  const grid_js_1 = require("./grid.js");
12
14
  function eposXmlEscape(text) {
13
15
  return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;');
14
16
  }
15
17
  const NS = 'http://www.epson-pos.com/schemas/2011/03/epos-print';
18
+ /** Nur das XML; wer die QR-Meldungen braucht, nimmt [eposPrintXmlErgebnis]. */
16
19
  function eposPrintXml(layout, options = {}) {
20
+ return eposPrintXmlErgebnis(layout, options).xml;
21
+ }
22
+ /**
23
+ * Wie [eposPrintXml], gibt aber zusaetzlich zurueck, was dem QR zugestossen
24
+ * ist.
25
+ *
26
+ * **Die QR-Modulgroesse wird gerechnet.** Vorher stand hier fest 6, unabhaengig
27
+ * von der Papierbreite: ein Beleg-QR mit realer RKSV-Nutzlast hat 57 Module,
28
+ * mit Ruhezone 65, bei sechs Punkten also 390 Druckpunkte -- und ein
29
+ * 58-mm-Kopf hat 384. Der Epson schneidet ein zu breites Symbol nicht ab, er
30
+ * laesst es weg; genau daran fehlte am echten Beleg der QR.
31
+ */
32
+ function eposPrintXmlErgebnis(layout, options = {}) {
17
33
  const grid = (0, grid_js_1.renderReceiptGrid)(layout, { zeichen: options.zeichen ?? grid_js_1.ZEICHEN_JE_PAPIER[layout.paperSize] });
18
- const qrBreite = Math.min(16, Math.max(3, Math.floor(options.qrBreite ?? 6)));
34
+ const deckel = options.qrGroesse ?? 'mittel';
35
+ const fest = options.qrBreite === undefined
36
+ ? null
37
+ : Math.min(16, Math.max(3, Math.floor(options.qrBreite)));
38
+ let qrFehler = null;
39
+ let qrAusweich = null;
40
+ /**
41
+ * Die Breite fuer eine QR-Zeile, oder `null` -- dann geht **kein** Symbol
42
+ * hinaus: ein Element, von dem man weiss, dass der Drucker es weglaesst,
43
+ * taeuscht nur einen Ausdruck vor.
44
+ *
45
+ * Eine leere Nutzlast geht unveraendert den Bestandsweg (Deckel), wie am
46
+ * ESC/POS-Befehl: sie ist ein Datenfehler, kein Papierfehler.
47
+ */
48
+ const qrBreiteFuer = (nutzlast) => {
49
+ if (fest !== null)
50
+ return fest;
51
+ if (nutzlast === '')
52
+ return index_js_1.QR_MODUL_DECKEL[deckel];
53
+ const mass = (0, index_js_1.qrGroesseFuer)({
54
+ nutzlast,
55
+ papierbreitePunkte: index_js_1.QR_DRUCK_PUNKTE[layout.paperSize],
56
+ groesse: deckel,
57
+ });
58
+ if (!mass.passt) {
59
+ qrFehler =
60
+ `QR mit ${mass.module} Modulen ist fuer ${layout.paperSize === 'mm58' ? 58 : 80} mm ` +
61
+ `(${index_js_1.QR_DRUCK_PUNKTE[layout.paperSize]} Punkte) zu breit`;
62
+ return null;
63
+ }
64
+ if (mass.unterMindestmass) {
65
+ qrAusweich =
66
+ `QR mit ${mass.module} Modulen passt nur mit ${String(mass.punkte)} Punkten ` +
67
+ `je Modul -- unter dem Mindestmass von ${index_js_1.QR_MINDEST_PUNKTE}`;
68
+ }
69
+ return mass.punkte;
70
+ };
19
71
  const out = [];
20
72
  out.push(`<epos-print xmlns="${NS}">`);
21
73
  out.push('<text lang="de"/>');
@@ -27,11 +79,15 @@ function eposPrintXml(layout, options = {}) {
27
79
  case 'space':
28
80
  out.push('<feed line="1"/>');
29
81
  break;
30
- case 'qr':
82
+ case 'qr': {
83
+ const breite = qrBreiteFuer(z.qr ?? '');
84
+ if (breite === null)
85
+ break;
31
86
  out.push('<text align="center"/>');
32
- out.push(`<symbol type="qrcode_model_2" level="level_m" width="${qrBreite}" height="0" size="0">${eposXmlEscape(z.qr ?? '')}</symbol>`);
87
+ out.push(`<symbol type="qrcode_model_2" level="level_m" width="${breite}" height="0" size="0">${eposXmlEscape(z.qr ?? '')}</symbol>`);
33
88
  out.push('<text align="left"/>');
34
89
  break;
90
+ }
35
91
  case 'banner':
36
92
  out.push(`<text width="1" height="2" reverse="${z.ton === 'warnung' ? 'true' : 'false'}" em="true">${eposXmlEscape(z.text)}&#10;</text>`);
37
93
  out.push('<text width="1" height="1" reverse="false" em="false"/>');
@@ -51,7 +107,7 @@ function eposPrintXml(layout, options = {}) {
51
107
  out.push('<cut type="feed"/>');
52
108
  }
53
109
  out.push('</epos-print>');
54
- return out.join('\n');
110
+ return { xml: out.join('\n'), qrFehler, qrAusweich };
55
111
  }
56
112
  const EPOS_DEVID_VORGABE = 'local_printer';
57
113
  function eposServiceUrl(ip, devid = EPOS_DEVID_VORGABE, timeoutMs = 10000) {
@@ -159,7 +215,12 @@ async function eposDirectSend(innerXml, o, fetchFn) {
159
215
  /** Beleg direkt drucken; wirft bei Netz-/Zertifikatsproblemen, sonst die Drucker-Antwort. */
160
216
  function eposDirectPrint(layout, o, fetchFn = fetch) {
161
217
  const papier = o.papier ?? layout.paperSize;
162
- return eposDirectSend(eposPrintXml({ ...layout, paperSize: papier }, { zeichen: grid_js_1.ZEICHEN_JE_PAPIER[papier] }), o, fetchFn);
218
+ const xmlOptionen = { zeichen: grid_js_1.ZEICHEN_JE_PAPIER[papier] };
219
+ if (o.qrBreite !== undefined)
220
+ xmlOptionen.qrBreite = o.qrBreite;
221
+ if (o.qrGroesse !== undefined)
222
+ xmlOptionen.qrGroesse = o.qrGroesse;
223
+ return eposDirectSend(eposPrintXml({ ...layout, paperSize: papier }, xmlOptionen), o, fetchFn);
163
224
  }
164
225
  /** Verbindungstest: leeres Dokument, druckt nichts, liefert den Druckerstatus. */
165
226
  function eposDirectStatus(o, fetchFn = fetch) {
@@ -1,4 +1,4 @@
1
1
  export { type LayoutAlign, type LayoutColumn, type LayoutTextLine, type LayoutColumnsLine, type LayoutRuleLine, type LayoutSpaceLine, type LayoutQrLine, type LayoutLine, type ReceiptLayout, type BuildReceiptLayoutOptions, buildReceiptLayout, receiptSignatureFailed, receiptSignatureIsTest, receiptIsZero, receiptAmountsAreZero, receiptIsSmallBusinessConsistent, receiptZdaText, type Pruefangaben, AKTUELLES_REGELWERK, type LayoutBannerLine, type LayoutRegelwerk, SMALL_BUSINESS_NOTICE, formatCents, } from './layout.js';
2
- export { type EscPosLayoutOptions, escPosLayoutBytes } from './layout-escpos.js';
2
+ export { type EscPosLayoutOptions, type EscPosLayoutErgebnis, type QrPrintMode, 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 EposDirectOptions, type EposResponse, EposConnectionError, eposPrintXml, eposXmlEscape, eposServiceUrl, eposSoapEnvelope, eposParseResponse, eposDirectPrint, eposDirectStatus } from './epos.js';
4
+ export { type EposPrintXmlOptions, type EposPrintErgebnis, type EposDirectOptions, type EposResponse, EposConnectionError, eposPrintXml, eposPrintXmlErgebnis, eposXmlEscape, eposServiceUrl, eposSoapEnvelope, eposParseResponse, eposDirectPrint, eposDirectStatus } from './epos.js';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.eposDirectStatus = exports.eposDirectPrint = exports.eposParseResponse = exports.eposSoapEnvelope = exports.eposServiceUrl = exports.eposXmlEscape = exports.eposPrintXml = exports.EposConnectionError = exports.ZEICHEN_JE_PAPIER = exports.gridAlsText = exports.gridSpaltenBreiten = exports.renderReceiptGrid = exports.escPosLayoutBytes = exports.formatCents = exports.SMALL_BUSINESS_NOTICE = exports.AKTUELLES_REGELWERK = exports.receiptZdaText = exports.receiptIsSmallBusinessConsistent = exports.receiptAmountsAreZero = exports.receiptIsZero = exports.receiptSignatureIsTest = exports.receiptSignatureFailed = exports.buildReceiptLayout = void 0;
3
+ exports.eposDirectStatus = exports.eposDirectPrint = exports.eposParseResponse = exports.eposSoapEnvelope = exports.eposServiceUrl = exports.eposXmlEscape = exports.eposPrintXmlErgebnis = exports.eposPrintXml = exports.EposConnectionError = exports.ZEICHEN_JE_PAPIER = exports.gridAlsText = exports.gridSpaltenBreiten = exports.renderReceiptGrid = exports.escPosLayoutErgebnis = exports.escPosLayoutBytes = exports.formatCents = exports.SMALL_BUSINESS_NOTICE = exports.AKTUELLES_REGELWERK = exports.receiptZdaText = exports.receiptIsSmallBusinessConsistent = exports.receiptAmountsAreZero = exports.receiptIsZero = exports.receiptSignatureIsTest = exports.receiptSignatureFailed = exports.buildReceiptLayout = void 0;
4
4
  var layout_js_1 = require("./layout.js");
5
5
  Object.defineProperty(exports, "buildReceiptLayout", { enumerable: true, get: function () { return layout_js_1.buildReceiptLayout; } });
6
6
  Object.defineProperty(exports, "receiptSignatureFailed", { enumerable: true, get: function () { return layout_js_1.receiptSignatureFailed; } });
@@ -14,6 +14,7 @@ Object.defineProperty(exports, "SMALL_BUSINESS_NOTICE", { enumerable: true, get:
14
14
  Object.defineProperty(exports, "formatCents", { enumerable: true, get: function () { return layout_js_1.formatCents; } });
15
15
  var layout_escpos_js_1 = require("./layout-escpos.js");
16
16
  Object.defineProperty(exports, "escPosLayoutBytes", { enumerable: true, get: function () { return layout_escpos_js_1.escPosLayoutBytes; } });
17
+ Object.defineProperty(exports, "escPosLayoutErgebnis", { enumerable: true, get: function () { return layout_escpos_js_1.escPosLayoutErgebnis; } });
17
18
  var grid_js_1 = require("./grid.js");
18
19
  Object.defineProperty(exports, "renderReceiptGrid", { enumerable: true, get: function () { return grid_js_1.renderReceiptGrid; } });
19
20
  Object.defineProperty(exports, "gridSpaltenBreiten", { enumerable: true, get: function () { return grid_js_1.gridSpaltenBreiten; } });
@@ -22,6 +23,7 @@ Object.defineProperty(exports, "ZEICHEN_JE_PAPIER", { enumerable: true, get: fun
22
23
  var epos_js_1 = require("./epos.js");
23
24
  Object.defineProperty(exports, "EposConnectionError", { enumerable: true, get: function () { return epos_js_1.EposConnectionError; } });
24
25
  Object.defineProperty(exports, "eposPrintXml", { enumerable: true, get: function () { return epos_js_1.eposPrintXml; } });
26
+ Object.defineProperty(exports, "eposPrintXmlErgebnis", { enumerable: true, get: function () { return epos_js_1.eposPrintXmlErgebnis; } });
25
27
  Object.defineProperty(exports, "eposXmlEscape", { enumerable: true, get: function () { return epos_js_1.eposXmlEscape; } });
26
28
  Object.defineProperty(exports, "eposServiceUrl", { enumerable: true, get: function () { return epos_js_1.eposServiceUrl; } });
27
29
  Object.defineProperty(exports, "eposSoapEnvelope", { enumerable: true, get: function () { return epos_js_1.eposSoapEnvelope; } });
@@ -1,4 +1,4 @@
1
- import { type PosCodeTable, type PosCutMode, type PosPaperSize, type QrCorrection, type QrSize } from '../printing/index.js';
1
+ import { type PosCodeTable, type PosCutMode, type PosPaperSize, type QrCorrection, type QrMatrix, type QrModulGroesse, type QrSize } from '../printing/index.js';
2
2
  import type { ReceiptLayout } from './layout.js';
3
3
  /**
4
4
  * Bruecke vom Layout-Modell zu ESC/POS-Bytes — der Bondrucker-Ausgabeweg.
@@ -14,6 +14,20 @@ import type { ReceiptLayout } from './layout.js';
14
14
  * ein unerwartetes Zeichen darin soll darum auffallen und nicht still
15
15
  * verfaelscht werden.
16
16
  */
17
+ /**
18
+ * Wie der Beleg-QR auf das Papier kommt — Zwilling von `QrPrintMode`
19
+ * (kasseneck_api/lib/enums/qr_print_mode.dart).
20
+ *
21
+ * - `native` — der Druckbefehl `GS ( k`; der Drucker zeichnet selbst.
22
+ * Ohne Modellbefehl, also byteidentisch zum Bestand.
23
+ * - `nativeModel1` — derselbe Befehl mit ausdruecklicher Wahl von **Modell 1**
24
+ * (`GS ( k 04 00 31 41 31 00`). Fuer guenstige Geraete, die
25
+ * nur diesen aelteren Symboltyp beherrschen; belegt ist
26
+ * eines, das bei Modell 2 unter dem Code eine "0" ausgibt.
27
+ * - `imageRaster` — der QR als Rasterbild. Braucht ein Raster vom Aufrufer
28
+ * (`qrMatrix`), weil dieses Paket keine QR-Codes rechnet.
29
+ */
30
+ export type QrPrintMode = 'native' | 'nativeModel1' | 'imageRaster';
17
31
  export interface EscPosLayoutOptions {
18
32
  /** Papierbreite; Vorgabe ist die des Layouts (dessen Spaltenbreiten daran haengen). */
19
33
  paperSize?: PosPaperSize;
@@ -21,10 +35,38 @@ export interface EscPosLayoutOptions {
21
35
  codeTable?: PosCodeTable | null;
22
36
  /** Papierschnitt am Ende: `true` (voll), `'partial'` oder `false`. Vorgabe `true`. */
23
37
  cut?: boolean | PosCutMode;
24
- /** Modulgroesse des QR-Codes. */
38
+ /**
39
+ * Feste Modulgroesse des QR-Codes. Gesetzt schaltet sie die Rechnung ab —
40
+ * dann passt der Aufrufer selbst auf, dass das Symbol aufs Papier geht.
41
+ */
25
42
  qrSize?: QrSize;
26
43
  /** Fehlerkorrekturstufe des QR-Codes. */
27
44
  qrCorrection?: QrCorrection;
45
+ /** Deckel fuer die gerechnete Modulgroesse; Vorgabe `auto`. */
46
+ qrGroesse?: QrModulGroesse;
47
+ /** Druckweg des QR; Vorgabe `native` (der Bestandsweg). */
48
+ qrModus?: QrPrintMode;
49
+ /**
50
+ * Raster fuer den Bildweg — ohne das gibt es keinen Notausgang.
51
+ *
52
+ * Dieses Paket rechnet keine QR-Codes und verarbeitet keine Bilder (siehe
53
+ * Kopf von `layout.ts`); der Aufrufer bringt das fertige Raster mit, etwa
54
+ * aus der QR-Bibliothek, die er ohnehin fuer den Bildschirm benutzt.
55
+ */
56
+ qrMatrix?: (nutzlast: string) => QrMatrix;
57
+ }
58
+ /**
59
+ * Der Bytestrom **samt** dem, was dem QR unterwegs zugestossen ist.
60
+ *
61
+ * Zwilling von `KeckPrintResult`: `qrFehler` heisst "Beleg ohne QR,
62
+ * nachdrucken oder elektronisch ausgeben", `qrAusweich` heisst "gedruckt,
63
+ * aber der eingestellte Weg taugt fuer dieses Geraet nicht" — das eine gehoert
64
+ * dem Kunden gesagt, das andere dem Chef.
65
+ */
66
+ export interface EscPosLayoutErgebnis {
67
+ bytes: Uint8Array;
68
+ qrFehler: string | null;
69
+ qrAusweich: string | null;
28
70
  }
29
71
  /**
30
72
  * Bytes fuer den Bondrucker -- **aus dem Zeichenraster** ([renderReceiptGrid]):
@@ -33,3 +75,9 @@ export interface EscPosLayoutOptions {
33
75
  * zeigt, druckt der Drucker (Monospace, Font A: 32/48 Zeichen).
34
76
  */
35
77
  export declare function escPosLayoutBytes(layout: ReceiptLayout, options?: EscPosLayoutOptions): Uint8Array;
78
+ /**
79
+ * Wie [escPosLayoutBytes], gibt aber zusaetzlich zurueck, was dem QR
80
+ * zugestossen ist. Die Bytes sind dieselben; wer die Meldungen braucht, nimmt
81
+ * diesen Weg.
82
+ */
83
+ export declare function escPosLayoutErgebnis(layout: ReceiptLayout, options?: EscPosLayoutOptions): EscPosLayoutErgebnis;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.escPosLayoutBytes = escPosLayoutBytes;
4
+ exports.escPosLayoutErgebnis = escPosLayoutErgebnis;
4
5
  const index_js_1 = require("../printing/index.js");
5
6
  const grid_js_1 = require("./grid.js");
6
7
  /**
@@ -29,6 +30,14 @@ function druckbaresLayout(layout) {
29
30
  * zeigt, druckt der Drucker (Monospace, Font A: 32/48 Zeichen).
30
31
  */
31
32
  function escPosLayoutBytes(layout, options = {}) {
33
+ return escPosLayoutErgebnis(layout, options).bytes;
34
+ }
35
+ /**
36
+ * Wie [escPosLayoutBytes], gibt aber zusaetzlich zurueck, was dem QR
37
+ * zugestossen ist. Die Bytes sind dieselben; wer die Meldungen braucht, nimmt
38
+ * diesen Weg.
39
+ */
40
+ function escPosLayoutErgebnis(layout, options = {}) {
32
41
  const paperSize = options.paperSize ?? layout.paperSize;
33
42
  const dokumentOptionen = { paperSize };
34
43
  if (options.codeTable !== undefined) {
@@ -36,11 +45,59 @@ function escPosLayoutBytes(layout, options = {}) {
36
45
  }
37
46
  const doc = (0, index_js_1.createEscPosDocument)(dokumentOptionen);
38
47
  (0, index_js_1.escPosReset)(doc);
48
+ const modus = options.qrModus ?? 'native';
39
49
  const qrOptionen = { align: 'center' };
40
50
  if (options.qrSize !== undefined)
41
51
  qrOptionen.size = options.qrSize;
42
52
  if (options.qrCorrection !== undefined)
43
53
  qrOptionen.correction = options.qrCorrection;
54
+ if (options.qrGroesse !== undefined)
55
+ qrOptionen.groesse = options.qrGroesse;
56
+ if (modus === 'nativeModel1')
57
+ qrOptionen.modell1 = true;
58
+ if (modus === 'imageRaster' && options.qrMatrix === undefined) {
59
+ throw new Error("qrModus 'imageRaster' braucht ein qrMatrix -- dieses Paket rastert nicht selbst");
60
+ }
61
+ const rasterOptionen = { align: 'center' };
62
+ if (options.qrGroesse !== undefined)
63
+ rasterOptionen.groesse = options.qrGroesse;
64
+ /**
65
+ * Eine QR-Zeile des Rasters. Hier sitzt der **Notausgang**: passt das Symbol
66
+ * nativ auch mit der Ausnahmegroesse nicht aufs Papier, druckt der Drucker
67
+ * es GAR NICHT -- er schneidet nicht ab, er laesst weg. Ein Pflichtbeleg
68
+ * ohne QR ist der schlechteste aller Ausgaenge, also geht der QR dann als
69
+ * Bild hinaus, und der Aufrufer erfaehrt es ueber `qrAusweich`.
70
+ *
71
+ * Ohne `qrMatrix` gibt es diesen Weg nicht -- dann bleibt nur die Meldung
72
+ * `qrFehler` aus `escPosQrCode`, und der Beleg geht ohne QR hinaus.
73
+ */
74
+ const qrZeile = (nutzlast) => {
75
+ const raster = options.qrMatrix;
76
+ if (nutzlast !== '' && raster !== undefined) {
77
+ if (modus === 'imageRaster') {
78
+ (0, index_js_1.escPosQrRaster)(doc, raster(nutzlast), rasterOptionen);
79
+ return;
80
+ }
81
+ // Feste `qrSize` heisst: der Aufrufer weiss, was er tut -- dann wird
82
+ // weder gerechnet noch ausgewichen.
83
+ if (options.qrSize === undefined) {
84
+ const mass = (0, index_js_1.qrGroesseFuer)({
85
+ nutzlast,
86
+ papierbreitePunkte: index_js_1.QR_DRUCK_PUNKTE[paperSize],
87
+ groesse: options.qrGroesse ?? 'auto',
88
+ });
89
+ if (!mass.passt) {
90
+ doc.qrAusweich =
91
+ `QR mit ${mass.module} Modulen passt nativ nicht auf ` +
92
+ `${paperSize === 'mm58' ? 58 : 80} mm (${index_js_1.QR_DRUCK_PUNKTE[paperSize]} Punkte) ` +
93
+ `-- als Bild gedruckt`;
94
+ (0, index_js_1.escPosQrRaster)(doc, raster(nutzlast), rasterOptionen);
95
+ return;
96
+ }
97
+ }
98
+ }
99
+ (0, index_js_1.escPosQrCode)(doc, nutzlast, qrOptionen);
100
+ };
44
101
  const grid = (0, grid_js_1.renderReceiptGrid)(druckbaresLayout(layout), { zeichen: grid_js_1.ZEICHEN_JE_PAPIER[paperSize] });
45
102
  for (const zeile of grid.lines) {
46
103
  switch (zeile.kind) {
@@ -48,7 +105,7 @@ function escPosLayoutBytes(layout, options = {}) {
48
105
  (0, index_js_1.escPosFeed)(doc, 1);
49
106
  break;
50
107
  case 'qr':
51
- (0, index_js_1.escPosQrCode)(doc, zeile.qr ?? '', qrOptionen);
108
+ qrZeile(zeile.qr ?? '');
52
109
  break;
53
110
  case 'banner': {
54
111
  // Belegart/Warnung: fett zwischen zwei Volllinien — derselbe Rahmen-
@@ -68,5 +125,5 @@ function escPosLayoutBytes(layout, options = {}) {
68
125
  if (options.cut !== false) {
69
126
  (0, index_js_1.escPosCut)(doc, options.cut === 'partial' ? 'partial' : 'full');
70
127
  }
71
- return (0, index_js_1.escPosBytes)(doc);
128
+ return { bytes: (0, index_js_1.escPosBytes)(doc), qrFehler: doc.qrFehler, qrAusweich: doc.qrAusweich };
72
129
  }
@@ -27,6 +27,7 @@
27
27
  * Nicht enthalten (bewusst): Rasterbilder/Logos, Capability-Profile einzelner
28
28
  * Druckermodelle, Kassenlade, 1D-Barcodes.
29
29
  */
30
+ import { type QrModulGroesse } from './qr-groesse.js';
30
31
  /** Papierbreite der Bonrolle. */
31
32
  export type PosPaperSize = 'mm58' | 'mm80';
32
33
  /** Ausrichtung einer Textzeile bzw. innerhalb einer Spalte. */
@@ -43,6 +44,14 @@ export type PosTextSize = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
43
44
  export type QrSize = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
44
45
  /** Fehlerkorrekturstufe des QR-Codes. */
45
46
  export type QrCorrection = 'L' | 'M' | 'Q' | 'H';
47
+ /**
48
+ * Fertig gerechnetes QR-Raster, quadratisch, `true` = schwarzes Modul —
49
+ * **ohne** Ruhezone, die setzt der Drucker-Weg selbst.
50
+ *
51
+ * Dieses Paket rastert bewusst nicht selbst (keine Bildverarbeitung, siehe
52
+ * Kopf dieser Datei); wer den Bildweg braucht, bringt sein eigenes Raster mit.
53
+ */
54
+ export type QrMatrix = readonly (readonly boolean[])[];
46
55
  /** Textstil. Fehlende Felder gelten als Vorgabewert (nicht als "unveraendert"). */
47
56
  export interface PosStyles {
48
57
  bold?: boolean;
@@ -88,8 +97,26 @@ export interface EscPosHrOptions {
88
97
  }
89
98
  export interface EscPosQrOptions {
90
99
  align?: PosAlign;
100
+ /**
101
+ * Feste Modulgroesse in Druckpunkten. Gesetzt schaltet sie die Rechnung ab —
102
+ * fuer Aufrufer, die genau wissen, was ihr Geraet kann. Ohne sie entscheidet
103
+ * die Regel in `qr-groesse.ts`.
104
+ */
91
105
  size?: QrSize;
92
106
  correction?: QrCorrection;
107
+ /** Deckel fuer die gerechnete Modulgroesse; wirkungslos neben `size`. */
108
+ groesse?: QrModulGroesse;
109
+ /** Modell 1 des Symbols ausdruecklich waehlen — siehe `qrCodeBytes`. */
110
+ modell1?: boolean;
111
+ }
112
+ export interface EscPosQrRasterOptions {
113
+ align?: PosAlign;
114
+ /** Feste Punkte je Modul; ohne Angabe gerechnet (mindestens 1). */
115
+ punkteJeModul?: number;
116
+ /** Deckel fuer die gerechnete Groesse. */
117
+ groesse?: QrModulGroesse;
118
+ /** Ruhezone je Seite in Modulen; Vorgabe `QR_RUHEZONE_MODULE` (4). */
119
+ ruhezoneModule?: number;
93
120
  }
94
121
  /** Interner Stilzustand — immer vollstaendig, nie teilbefuellt. */
95
122
  interface AktuelleStile {
@@ -111,6 +138,25 @@ interface AktuelleStile {
111
138
  export interface EscPosDocument {
112
139
  readonly paperSize: PosPaperSize;
113
140
  readonly spaceBetweenRows: number;
141
+ /**
142
+ * Der Beleg ging ohne QR hinaus — `null`, solange alles in Ordnung ist.
143
+ * Gesetzt, wenn das Symbol auch mit der Ausnahmegroesse nicht auf das Papier
144
+ * passt und kein Bildweg mitgegeben wurde. Auf einer oesterreichischen Kassa
145
+ * ist der QR die maschinenlesbare Signatur: das muss der Aufrufer erfahren,
146
+ * ohne den Bytestrom zu durchsuchen.
147
+ */
148
+ qrFehler: string | null;
149
+ /**
150
+ * Der QR steht auf dem Papier, aber nicht so wie eingestellt — `null`,
151
+ * solange nichts abgewichen ist. Zwei Faelle, beide mit Grund im Text: das
152
+ * Symbol war fuer den nativen Befehl zu breit und ging als Bild hinaus, oder
153
+ * es passte nur unter der Mindest-Modulgroesse.
154
+ *
155
+ * Getrennt von `qrFehler`, weil die Handlung eine andere ist: dort heisst es
156
+ * "Beleg ohne QR, nachdrucken oder elektronisch ausgeben", hier "gedruckt,
157
+ * aber der eingestellte Weg taugt fuer dieses Geraet nicht".
158
+ */
159
+ qrAusweich: string | null;
114
160
  /** intern: bisher erzeugte Bytes */
115
161
  readonly bytes: number[];
116
162
  /** intern: global gesetzte Codepage (ueberlebt `escPosReset`) */
@@ -213,7 +259,45 @@ export declare function escPosRow(doc: EscPosDocument, columns: readonly PosColu
213
259
  export declare function qrCodeBytes(text: string, options?: {
214
260
  size?: QrSize;
215
261
  correction?: QrCorrection;
262
+ modell1?: boolean;
216
263
  }): Uint8Array;
217
- /** Setzt die Ausrichtung und haengt den nativen QR-Befehl an. */
264
+ /**
265
+ * Setzt die Ausrichtung und haengt den nativen QR-Befehl an — mit
266
+ * **gerechneter** Modulgroesse, sofern `options.size` sie nicht festlegt.
267
+ *
268
+ * Ohne `size` entscheidet die Regel aus `qr-groesse.ts`: so gross wie
269
+ * moeglich, gedeckelt durch `options.groesse` (Vorgabe `auto` = der
270
+ * Bestandswert 4 dieses Pakets). Passt das Symbol auch mit der
271
+ * Ausnahmegroesse nicht aufs Papier, geht **kein** QR-Befehl hinaus und
272
+ * `doc.qrFehler` sagt warum: der Drucker schneidet ein zu breites Symbol
273
+ * nicht ab, er laesst es weg — ein Befehl, von dem man weiss, dass er nichts
274
+ * druckt, taeuschte nur einen Ausdruck vor. Den Bildweg kennt diese Ebene
275
+ * nicht; den faehrt `escPosQrRaster` bzw. der Belegweg in `layout-escpos.ts`.
276
+ *
277
+ * Eine leere Nutzlast geht unveraendert durch (fester Bestandsweg, keine
278
+ * Rechnung): sie ist ein Datenfehler, kein Papierfehler, und der Aufrufer
279
+ * behandelt sie ohnehin schon.
280
+ */
218
281
  export declare function escPosQrCode(doc: EscPosDocument, text: string, options?: EscPosQrOptions): void;
282
+ /**
283
+ * Der Bildweg: ein fertiges QR-Raster als Rasterbild (`GS v 0`) — der
284
+ * Notausgang, wenn der native Befehl das Symbol nicht auf das Papier bringt.
285
+ *
286
+ * Ein Pflichtbeleg ohne QR ist der schlechteste aller Ausgaenge; als Bild
287
+ * geht jedes Symbol hinaus, weil die Punkte je Modul hier bis auf 1 fallen
288
+ * duerfen. Dafuer ist das Bild langsamer und auf manchen Geraeten blasser.
289
+ *
290
+ * Das Raster selbst kommt vom Aufrufer (siehe `QrMatrix`): dieses Paket
291
+ * rechnet keine QR-Codes und verarbeitet keine Bilder.
292
+ */
293
+ export declare function escPosQrRaster(doc: EscPosDocument, matrix: QrMatrix, options?: EscPosQrRasterOptions): void;
294
+ /**
295
+ * Punkte je Modul, mit denen `escPosQrRaster` ein Raster dieser Groesse auf
296
+ * dieses Papier bringt — dieselbe Rechnung, nur ohne Untergrenze 3: ein Bild
297
+ * darf bis auf einen Punkt je Modul schrumpfen und passt darum immer.
298
+ */
299
+ export declare function qrRasterPunkte(paperSize: PosPaperSize, moduleAnzahl: number, options?: {
300
+ groesse?: QrModulGroesse;
301
+ ruhezoneModule?: number;
302
+ }): number;
219
303
  export {};