@kreiseck/kasseneck-api 0.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (294) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +2 -0
  3. package/README.md +206 -0
  4. package/dist/cjs/client/api.d.ts +75 -0
  5. package/dist/cjs/client/api.js +40 -0
  6. package/dist/cjs/client/auth.d.ts +52 -0
  7. package/dist/cjs/client/auth.js +72 -0
  8. package/dist/cjs/client/cashregisters.d.ts +21 -0
  9. package/dist/cjs/client/cashregisters.js +36 -0
  10. package/dist/cjs/client/errors.d.ts +159 -0
  11. package/dist/cjs/client/errors.js +226 -0
  12. package/dist/cjs/client/index.d.ts +8 -0
  13. package/dist/cjs/client/index.js +44 -0
  14. package/dist/cjs/client/receipts.d.ts +245 -0
  15. package/dist/cjs/client/receipts.js +452 -0
  16. package/dist/cjs/client/reports.d.ts +43 -0
  17. package/dist/cjs/client/reports.js +73 -0
  18. package/dist/cjs/client/status.d.ts +43 -0
  19. package/dist/cjs/client/status.js +47 -0
  20. package/dist/cjs/client/transport.d.ts +117 -0
  21. package/dist/cjs/client/transport.js +312 -0
  22. package/dist/cjs/enums/credit-card-provider.d.ts +22 -0
  23. package/dist/cjs/enums/credit-card-provider.js +23 -0
  24. package/dist/cjs/enums/define-enum.d.ts +15 -0
  25. package/dist/cjs/enums/define-enum.js +16 -0
  26. package/dist/cjs/enums/index.d.ts +7 -0
  27. package/dist/cjs/enums/index.js +17 -0
  28. package/dist/cjs/enums/keck-payment-method.d.ts +57 -0
  29. package/dist/cjs/enums/keck-payment-method.js +23 -0
  30. package/dist/cjs/enums/receipt-type.d.ts +41 -0
  31. package/dist/cjs/enums/receipt-type.js +18 -0
  32. package/dist/cjs/enums/stripe-link-mode.d.ts +17 -0
  33. package/dist/cjs/enums/stripe-link-mode.js +18 -0
  34. package/dist/cjs/enums/vat-rate.d.ts +40 -0
  35. package/dist/cjs/enums/vat-rate.js +19 -0
  36. package/dist/cjs/enums/voucher-action.d.ts +10 -0
  37. package/dist/cjs/enums/voucher-action.js +11 -0
  38. package/dist/cjs/enums/voucher-type.d.ts +9 -0
  39. package/dist/cjs/enums/voucher-type.js +10 -0
  40. package/dist/cjs/index.d.ts +5 -0
  41. package/dist/cjs/index.js +97 -0
  42. package/dist/cjs/kasse/artikel.d.ts +83 -0
  43. package/dist/cjs/kasse/artikel.js +79 -0
  44. package/dist/cjs/kasse/client.d.ts +10 -0
  45. package/dist/cjs/kasse/client.js +38 -0
  46. package/dist/cjs/kasse/drucker.d.ts +54 -0
  47. package/dist/cjs/kasse/drucker.js +41 -0
  48. package/dist/cjs/kasse/index.d.ts +11 -0
  49. package/dist/cjs/kasse/index.js +38 -0
  50. package/dist/cjs/kasse/settings.d.ts +115 -0
  51. package/dist/cjs/kasse/settings.js +62 -0
  52. package/dist/cjs/models/cancellation.d.ts +51 -0
  53. package/dist/cjs/models/cancellation.js +45 -0
  54. package/dist/cjs/models/cashregister.d.ts +77 -0
  55. package/dist/cjs/models/cashregister.js +53 -0
  56. package/dist/cjs/models/enum-payload.d.ts +26 -0
  57. package/dist/cjs/models/enum-payload.js +50 -0
  58. package/dist/cjs/models/hobex-receipt.d.ts +63 -0
  59. package/dist/cjs/models/hobex-receipt.js +86 -0
  60. package/dist/cjs/models/index.d.ts +10 -0
  61. package/dist/cjs/models/index.js +46 -0
  62. package/dist/cjs/models/receipt-company.d.ts +71 -0
  63. package/dist/cjs/models/receipt-company.js +52 -0
  64. package/dist/cjs/models/receipt-item.d.ts +100 -0
  65. package/dist/cjs/models/receipt-item.js +108 -0
  66. package/dist/cjs/models/receipt-summary.d.ts +92 -0
  67. package/dist/cjs/models/receipt-summary.js +54 -0
  68. package/dist/cjs/models/receipt.d.ts +108 -0
  69. package/dist/cjs/models/receipt.js +119 -0
  70. package/dist/cjs/models/report-month.d.ts +32 -0
  71. package/dist/cjs/models/report-month.js +65 -0
  72. package/dist/cjs/models/stripe-url-session.d.ts +18 -0
  73. package/dist/cjs/models/stripe-url-session.js +20 -0
  74. package/dist/cjs/models/voucher.d.ts +41 -0
  75. package/dist/cjs/models/voucher.js +56 -0
  76. package/dist/cjs/money.d.ts +23 -0
  77. package/dist/cjs/money.js +35 -0
  78. package/dist/cjs/package.json +1 -0
  79. package/dist/cjs/payments/hobex.d.ts +87 -0
  80. package/dist/cjs/payments/hobex.js +167 -0
  81. package/dist/cjs/payments/index.d.ts +33 -0
  82. package/dist/cjs/payments/index.js +42 -0
  83. package/dist/cjs/payments/stripe.d.ts +61 -0
  84. package/dist/cjs/payments/stripe.js +157 -0
  85. package/dist/cjs/printing/escpos.d.ts +219 -0
  86. package/dist/cjs/printing/escpos.js +636 -0
  87. package/dist/cjs/printing/index.d.ts +3 -0
  88. package/dist/cjs/printing/index.js +33 -0
  89. package/dist/cjs/printing/printable.d.ts +27 -0
  90. package/dist/cjs/printing/printable.js +90 -0
  91. package/dist/cjs/printing/webusb.d.ts +89 -0
  92. package/dist/cjs/printing/webusb.js +110 -0
  93. package/dist/cjs/react/index.d.ts +46 -0
  94. package/dist/cjs/react/index.js +51 -0
  95. package/dist/cjs/receipt/discount.d.ts +12 -0
  96. package/dist/cjs/receipt/discount.js +54 -0
  97. package/dist/cjs/receipt/epos.d.ts +53 -0
  98. package/dist/cjs/receipt/epos.js +95 -0
  99. package/dist/cjs/receipt/grid.d.ts +47 -0
  100. package/dist/cjs/receipt/grid.js +122 -0
  101. package/dist/cjs/receipt/index.d.ts +4 -0
  102. package/dist/cjs/receipt/index.js +29 -0
  103. package/dist/cjs/receipt/layout-escpos.d.ts +35 -0
  104. package/dist/cjs/receipt/layout-escpos.js +67 -0
  105. package/dist/cjs/receipt/layout.d.ts +180 -0
  106. package/dist/cjs/receipt/layout.js +594 -0
  107. package/dist/cjs/register/index.d.ts +51 -0
  108. package/dist/cjs/register/index.js +61 -0
  109. package/dist/cjs/register/pairing.d.ts +248 -0
  110. package/dist/cjs/register/pairing.js +279 -0
  111. package/dist/cjs/register/session.d.ts +37 -0
  112. package/dist/cjs/register/session.js +52 -0
  113. package/dist/cjs/vienna-time.d.ts +23 -0
  114. package/dist/cjs/vienna-time.js +114 -0
  115. package/dist/esm/client/api.d.ts +75 -0
  116. package/dist/esm/client/api.js +37 -0
  117. package/dist/esm/client/auth.d.ts +52 -0
  118. package/dist/esm/client/auth.js +68 -0
  119. package/dist/esm/client/cashregisters.d.ts +21 -0
  120. package/dist/esm/client/cashregisters.js +33 -0
  121. package/dist/esm/client/errors.d.ts +159 -0
  122. package/dist/esm/client/errors.js +212 -0
  123. package/dist/esm/client/index.d.ts +8 -0
  124. package/dist/esm/client/index.js +8 -0
  125. package/dist/esm/client/receipts.d.ts +245 -0
  126. package/dist/esm/client/receipts.js +438 -0
  127. package/dist/esm/client/reports.d.ts +43 -0
  128. package/dist/esm/client/reports.js +69 -0
  129. package/dist/esm/client/status.d.ts +43 -0
  130. package/dist/esm/client/status.js +43 -0
  131. package/dist/esm/client/transport.d.ts +117 -0
  132. package/dist/esm/client/transport.js +307 -0
  133. package/dist/esm/enums/credit-card-provider.d.ts +22 -0
  134. package/dist/esm/enums/credit-card-provider.js +20 -0
  135. package/dist/esm/enums/define-enum.d.ts +15 -0
  136. package/dist/esm/enums/define-enum.js +13 -0
  137. package/dist/esm/enums/index.d.ts +7 -0
  138. package/dist/esm/enums/index.js +7 -0
  139. package/dist/esm/enums/keck-payment-method.d.ts +57 -0
  140. package/dist/esm/enums/keck-payment-method.js +20 -0
  141. package/dist/esm/enums/receipt-type.d.ts +41 -0
  142. package/dist/esm/enums/receipt-type.js +15 -0
  143. package/dist/esm/enums/stripe-link-mode.d.ts +17 -0
  144. package/dist/esm/enums/stripe-link-mode.js +15 -0
  145. package/dist/esm/enums/vat-rate.d.ts +40 -0
  146. package/dist/esm/enums/vat-rate.js +16 -0
  147. package/dist/esm/enums/voucher-action.d.ts +10 -0
  148. package/dist/esm/enums/voucher-action.js +8 -0
  149. package/dist/esm/enums/voucher-type.d.ts +9 -0
  150. package/dist/esm/enums/voucher-type.js +7 -0
  151. package/dist/esm/index.d.ts +5 -0
  152. package/dist/esm/index.js +5 -0
  153. package/dist/esm/kasse/artikel.d.ts +83 -0
  154. package/dist/esm/kasse/artikel.js +70 -0
  155. package/dist/esm/kasse/client.d.ts +10 -0
  156. package/dist/esm/kasse/client.js +33 -0
  157. package/dist/esm/kasse/drucker.d.ts +54 -0
  158. package/dist/esm/kasse/drucker.js +36 -0
  159. package/dist/esm/kasse/index.d.ts +11 -0
  160. package/dist/esm/kasse/index.js +13 -0
  161. package/dist/esm/kasse/settings.d.ts +115 -0
  162. package/dist/esm/kasse/settings.js +58 -0
  163. package/dist/esm/models/cancellation.d.ts +51 -0
  164. package/dist/esm/models/cancellation.js +40 -0
  165. package/dist/esm/models/cashregister.d.ts +77 -0
  166. package/dist/esm/models/cashregister.js +50 -0
  167. package/dist/esm/models/enum-payload.d.ts +26 -0
  168. package/dist/esm/models/enum-payload.js +44 -0
  169. package/dist/esm/models/hobex-receipt.d.ts +63 -0
  170. package/dist/esm/models/hobex-receipt.js +80 -0
  171. package/dist/esm/models/index.d.ts +10 -0
  172. package/dist/esm/models/index.js +10 -0
  173. package/dist/esm/models/receipt-company.d.ts +71 -0
  174. package/dist/esm/models/receipt-company.js +48 -0
  175. package/dist/esm/models/receipt-item.d.ts +100 -0
  176. package/dist/esm/models/receipt-item.js +101 -0
  177. package/dist/esm/models/receipt-summary.d.ts +92 -0
  178. package/dist/esm/models/receipt-summary.js +49 -0
  179. package/dist/esm/models/receipt.d.ts +108 -0
  180. package/dist/esm/models/receipt.js +113 -0
  181. package/dist/esm/models/report-month.d.ts +32 -0
  182. package/dist/esm/models/report-month.js +58 -0
  183. package/dist/esm/models/stripe-url-session.d.ts +18 -0
  184. package/dist/esm/models/stripe-url-session.js +16 -0
  185. package/dist/esm/models/voucher.d.ts +41 -0
  186. package/dist/esm/models/voucher.js +51 -0
  187. package/dist/esm/money.d.ts +23 -0
  188. package/dist/esm/money.js +31 -0
  189. package/dist/esm/payments/hobex.d.ts +87 -0
  190. package/dist/esm/payments/hobex.js +162 -0
  191. package/dist/esm/payments/index.d.ts +33 -0
  192. package/dist/esm/payments/index.js +33 -0
  193. package/dist/esm/payments/stripe.d.ts +61 -0
  194. package/dist/esm/payments/stripe.js +153 -0
  195. package/dist/esm/printing/escpos.d.ts +219 -0
  196. package/dist/esm/printing/escpos.js +616 -0
  197. package/dist/esm/printing/index.d.ts +3 -0
  198. package/dist/esm/printing/index.js +3 -0
  199. package/dist/esm/printing/printable.d.ts +27 -0
  200. package/dist/esm/printing/printable.js +87 -0
  201. package/dist/esm/printing/webusb.d.ts +89 -0
  202. package/dist/esm/printing/webusb.js +101 -0
  203. package/dist/esm/react/index.d.ts +46 -0
  204. package/dist/esm/react/index.js +47 -0
  205. package/dist/esm/receipt/discount.d.ts +12 -0
  206. package/dist/esm/receipt/discount.js +51 -0
  207. package/dist/esm/receipt/epos.d.ts +53 -0
  208. package/dist/esm/receipt/epos.js +86 -0
  209. package/dist/esm/receipt/grid.d.ts +47 -0
  210. package/dist/esm/receipt/grid.js +116 -0
  211. package/dist/esm/receipt/index.d.ts +4 -0
  212. package/dist/esm/receipt/index.js +4 -0
  213. package/dist/esm/receipt/layout-escpos.d.ts +35 -0
  214. package/dist/esm/receipt/layout-escpos.js +64 -0
  215. package/dist/esm/receipt/layout.d.ts +180 -0
  216. package/dist/esm/receipt/layout.js +583 -0
  217. package/dist/esm/register/index.d.ts +51 -0
  218. package/dist/esm/register/index.js +51 -0
  219. package/dist/esm/register/pairing.d.ts +248 -0
  220. package/dist/esm/register/pairing.js +270 -0
  221. package/dist/esm/register/session.d.ts +37 -0
  222. package/dist/esm/register/session.js +48 -0
  223. package/dist/esm/vienna-time.d.ts +23 -0
  224. package/dist/esm/vienna-time.js +110 -0
  225. package/fixtures/belege/langer-artikelname.json +43 -0
  226. package/fixtures/belege/null-ausfall.json +41 -0
  227. package/fixtures/belege/null-jahr.json +41 -0
  228. package/fixtures/belege/null-monat.json +41 -0
  229. package/fixtures/belege/null-pruef.json +41 -0
  230. package/fixtures/belege/null-schluss.json +41 -0
  231. package/fixtures/belege/null-start.json +40 -0
  232. package/fixtures/belege/rabattzeilen.json +61 -0
  233. package/fixtures/belege/signaturausfall-verkauf.json +49 -0
  234. package/fixtures/belege/storno-teil.json +48 -0
  235. package/fixtures/belege/storno-voll.json +54 -0
  236. package/fixtures/belege/testkasse-verkauf.json +50 -0
  237. package/fixtures/belege/testsignatur-verkauf.json +50 -0
  238. package/fixtures/belege/training.json +49 -0
  239. package/fixtures/belege/verkauf-bar.json +49 -0
  240. package/fixtures/belege/verkauf-karte.json +49 -0
  241. package/fixtures/belege/verkauf-kleinunternehmer.json +42 -0
  242. package/fixtures/erwartet/langer-artikelname.grid32.txt +25 -0
  243. package/fixtures/erwartet/langer-artikelname.grid48.txt +24 -0
  244. package/fixtures/erwartet/langer-artikelname.lines.json +216 -0
  245. package/fixtures/erwartet/null-ausfall.grid32.txt +28 -0
  246. package/fixtures/erwartet/null-ausfall.grid48.txt +25 -0
  247. package/fixtures/erwartet/null-ausfall.lines.json +220 -0
  248. package/fixtures/erwartet/null-jahr.grid32.txt +29 -0
  249. package/fixtures/erwartet/null-jahr.grid48.txt +25 -0
  250. package/fixtures/erwartet/null-jahr.lines.json +220 -0
  251. package/fixtures/erwartet/null-monat.grid32.txt +28 -0
  252. package/fixtures/erwartet/null-monat.grid48.txt +25 -0
  253. package/fixtures/erwartet/null-monat.lines.json +220 -0
  254. package/fixtures/erwartet/null-pruef.grid32.txt +28 -0
  255. package/fixtures/erwartet/null-pruef.grid48.txt +25 -0
  256. package/fixtures/erwartet/null-pruef.lines.json +220 -0
  257. package/fixtures/erwartet/null-schluss.grid32.txt +28 -0
  258. package/fixtures/erwartet/null-schluss.grid48.txt +25 -0
  259. package/fixtures/erwartet/null-schluss.lines.json +220 -0
  260. package/fixtures/erwartet/null-start.grid32.txt +28 -0
  261. package/fixtures/erwartet/null-start.grid48.txt +25 -0
  262. package/fixtures/erwartet/null-start.lines.json +220 -0
  263. package/fixtures/erwartet/rabattzeilen.grid32.txt +27 -0
  264. package/fixtures/erwartet/rabattzeilen.grid48.txt +26 -0
  265. package/fixtures/erwartet/rabattzeilen.lines.json +286 -0
  266. package/fixtures/erwartet/signaturausfall-verkauf.grid32.txt +28 -0
  267. package/fixtures/erwartet/signaturausfall-verkauf.grid48.txt +26 -0
  268. package/fixtures/erwartet/signaturausfall-verkauf.lines.json +266 -0
  269. package/fixtures/erwartet/storno-teil.grid32.txt +27 -0
  270. package/fixtures/erwartet/storno-teil.grid48.txt +26 -0
  271. package/fixtures/erwartet/storno-teil.lines.json +237 -0
  272. package/fixtures/erwartet/storno-voll.grid32.txt +29 -0
  273. package/fixtures/erwartet/storno-voll.grid48.txt +28 -0
  274. package/fixtures/erwartet/storno-voll.lines.json +277 -0
  275. package/fixtures/erwartet/testkasse-verkauf.grid32.txt +28 -0
  276. package/fixtures/erwartet/testkasse-verkauf.grid48.txt +27 -0
  277. package/fixtures/erwartet/testkasse-verkauf.lines.json +270 -0
  278. package/fixtures/erwartet/testsignatur-verkauf.grid32.txt +30 -0
  279. package/fixtures/erwartet/testsignatur-verkauf.grid48.txt +27 -0
  280. package/fixtures/erwartet/testsignatur-verkauf.lines.json +270 -0
  281. package/fixtures/erwartet/training.grid32.txt +33 -0
  282. package/fixtures/erwartet/training.grid48.txt +30 -0
  283. package/fixtures/erwartet/training.lines.json +277 -0
  284. package/fixtures/erwartet/verkauf-bar.grid32.txt +25 -0
  285. package/fixtures/erwartet/verkauf-bar.grid48.txt +24 -0
  286. package/fixtures/erwartet/verkauf-bar.lines.json +256 -0
  287. package/fixtures/erwartet/verkauf-karte.grid32.txt +25 -0
  288. package/fixtures/erwartet/verkauf-karte.grid48.txt +24 -0
  289. package/fixtures/erwartet/verkauf-karte.lines.json +256 -0
  290. package/fixtures/erwartet/verkauf-kleinunternehmer.grid32.txt +26 -0
  291. package/fixtures/erwartet/verkauf-kleinunternehmer.grid48.txt +25 -0
  292. package/fixtures/erwartet/verkauf-kleinunternehmer.lines.json +226 -0
  293. package/fixtures/manifest.json +107 -0
  294. package/package.json +135 -0
@@ -0,0 +1,116 @@
1
+ import { wortzeilenText } from '../printing/escpos.js';
2
+ /**
3
+ * Zeichenraster: der Beleg als Zeilen mit **exakt N Zeichen** -- die einzige
4
+ * Wahrheit fuer Bildschirm, Bondruck und PDF. Kein Ausgabeweg rechnet
5
+ * Spalten selbst; wer das Raster setzt, setzt den Beleg.
6
+ *
7
+ * Regeln (fest, damit ueberall dasselbe herauskommt):
8
+ * - Papier 58 mm = 32 Zeichen, 80 mm = 48 (Font A); andere Breiten per Option.
9
+ * - Spalten in Zwoelfteln -> ganze Zeichen: `floor(N*w/12)`, der Rest an die
10
+ * letzte Spalte, jede mindestens 1. Zwischen zwei Spalten steht immer
11
+ * mindestens ein Leerzeichen (letztes Zeichen jeder nicht-letzten Spalte).
12
+ * Die letzte Spalte endet buendig am rechten Rand.
13
+ * - Text/Aufdruck/Spalteninhalt bricht **wortweise** um (`wortzeilenText`,
14
+ * dieselbe Regel wie der ESC/POS-Kern); ueberlange Woerter nach einem
15
+ * Bindestrich, sonst hart; geschuetztes Leerzeichen bricht nie.
16
+ * - Fliessregel: laeuft in einer Spaltenzeile nur eine Spalte ueber die erste
17
+ * Zeile hinaus, bekommt ihr Rest die volle Breite (lange Artikelnamen auf
18
+ * 58 mm); laufen mehrere weiter, bleibt das Raster.
19
+ * - Trennlinie ueber die volle Breite, Leerraum als Leerzeilen, QR als eigene
20
+ * Zeile mit Nutzlast (der Zeichner setzt das Bild).
21
+ */
22
+ export const ZEICHEN_JE_PAPIER = { mm58: 32, mm80: 48 };
23
+ /** Zwoelftel -> Zeichen je Spalte (ganze Zeichen, Rest an die letzte, mindestens 1). */
24
+ export function gridSpaltenBreiten(zwoelftel, zeichen) {
25
+ const out = [];
26
+ let vergeben = 0;
27
+ zwoelftel.forEach((w, i) => {
28
+ const letzte = i === zwoelftel.length - 1;
29
+ const b = letzte ? Math.max(1, zeichen - vergeben) : Math.max(1, Math.floor((zeichen * w) / 12));
30
+ out.push(b);
31
+ vergeben += b;
32
+ });
33
+ return out;
34
+ }
35
+ function ausrichten(text, breite, align) {
36
+ const t = text.length > breite ? text.slice(0, breite) : text;
37
+ const rest = breite - t.length;
38
+ if (align === 'right')
39
+ return ' '.repeat(rest) + t;
40
+ if (align === 'center') {
41
+ const links = Math.floor(rest / 2);
42
+ return ' '.repeat(links) + t + ' '.repeat(rest - links);
43
+ }
44
+ return t + ' '.repeat(rest);
45
+ }
46
+ const QR_PLATZHALTER = '[QR-Code]';
47
+ /** Text hinter der ersten Umbruchzeile (die ist ein Praefix des Textes, ohne Endleerzeichen). */
48
+ function restNach(text, erste) {
49
+ let i = erste.length;
50
+ while (i < text.length && text[i] === ' ')
51
+ i += 1;
52
+ return text.slice(i);
53
+ }
54
+ export function renderReceiptGrid(layout, options = {}) {
55
+ const zeichen = Math.max(8, Math.floor(options.zeichen ?? ZEICHEN_JE_PAPIER[layout.paperSize] ?? 32));
56
+ const leer = ' '.repeat(zeichen);
57
+ const lines = [];
58
+ for (const z of layout.lines) {
59
+ switch (z.kind) {
60
+ case 'text':
61
+ for (const t of wortzeilenText(z.text, zeichen))
62
+ lines.push({ text: ausrichten(t, zeichen, z.align), kind: 'text', bold: z.bold });
63
+ break;
64
+ case 'banner':
65
+ for (const t of wortzeilenText(z.text, zeichen))
66
+ lines.push({ text: ausrichten(t, zeichen, 'center'), kind: 'banner', bold: true, ton: z.ton });
67
+ break;
68
+ case 'rule':
69
+ lines.push({ text: (z.char || '-').charAt(0).repeat(zeichen), kind: 'rule', bold: false });
70
+ break;
71
+ case 'space':
72
+ for (let i = 0; i < Math.max(0, z.lines); i += 1)
73
+ lines.push({ text: leer, kind: 'space', bold: false });
74
+ break;
75
+ case 'qr':
76
+ lines.push({ text: ausrichten(QR_PLATZHALTER, zeichen, 'center'), kind: 'qr', bold: false, qr: z.data });
77
+ break;
78
+ case 'columns': {
79
+ const breiten = gridSpaltenBreiten(z.columns.map((c) => c.width), zeichen);
80
+ // Inhalt jeder nicht-letzten Spalte um 1 Zeichen schmaler: garantierter Abstand.
81
+ const inhalt = breiten.map((b, i) => (i < breiten.length - 1 ? Math.max(1, b - 1) : b));
82
+ const teile = z.columns.map((c, i) => wortzeilenText(c.text, inhalt[i]));
83
+ // Fliessregel: laeuft nach der ersten Zeile nur noch EINE Spalte weiter (die anderen sind
84
+ // fertig), bekommt ihr Rest die volle Breite -- auf 58 mm sonst 18-Zeichen-Schnipsel.
85
+ // Laufen mehrere weiter, bleibt das Raster (sonst verschoeben sich die Nachbarn).
86
+ const weiterlaufend = teile.map((t, i) => (t.length > 1 ? i : -1)).filter((i) => i >= 0);
87
+ const fliesst = weiterlaufend.length === 1 && z.columns.length > 1;
88
+ const zeilen = fliesst ? 1 : Math.max(1, ...teile.map((t) => t.length));
89
+ for (let r = 0; r < zeilen; r += 1) {
90
+ let text = '';
91
+ z.columns.forEach((c, i) => {
92
+ const zelle = ausrichten(teile[i][r] ?? '', inhalt[i], c.align);
93
+ text += i < breiten.length - 1 ? zelle + ' '.repeat(breiten[i] - inhalt[i]) : zelle;
94
+ });
95
+ lines.push({ text: text.length === zeichen ? text : ausrichten(text, zeichen, 'left'), kind: 'columns', bold: false });
96
+ }
97
+ if (fliesst) {
98
+ const i = weiterlaufend[0];
99
+ // Rest aus dem Originaltext (nicht aus den schmal umbrochenen Stuecken), damit
100
+ // Bindestrich-/Hartbrueche der schmalen Spalte nicht als Leerzeichen zurueckbleiben.
101
+ const rest = restNach(z.columns[i].text, teile[i][0]);
102
+ for (const t of wortzeilenText(rest, zeichen))
103
+ lines.push({ text: ausrichten(t, zeichen, z.columns[i].align), kind: 'columns', bold: false });
104
+ }
105
+ break;
106
+ }
107
+ default:
108
+ break;
109
+ }
110
+ }
111
+ return { lines, zeichen };
112
+ }
113
+ /** Klartext (eine Zeile je Rasterzeile) -- fuer Golden-Dateien und Logs. QR als Platzhalter. */
114
+ export function gridAlsText(grid) {
115
+ return grid.lines.map((z) => z.text).join('\n');
116
+ }
@@ -0,0 +1,4 @@
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';
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, eposPrintXml, eposXmlEscape, eposServiceUrl, eposSoapEnvelope, eposParseResponse, eposDirectPrint, eposDirectStatus } from './epos.js';
@@ -0,0 +1,4 @@
1
+ export { buildReceiptLayout, receiptSignatureFailed, receiptSignatureIsTest, receiptIsZero, receiptAmountsAreZero, receiptIsSmallBusinessConsistent, receiptZdaText, AKTUELLES_REGELWERK, SMALL_BUSINESS_NOTICE, formatCents, } from './layout.js';
2
+ export { escPosLayoutBytes } from './layout-escpos.js';
3
+ export { renderReceiptGrid, gridSpaltenBreiten, gridAlsText, ZEICHEN_JE_PAPIER, } from './grid.js';
4
+ export { eposPrintXml, eposXmlEscape, eposServiceUrl, eposSoapEnvelope, eposParseResponse, eposDirectPrint, eposDirectStatus } from './epos.js';
@@ -0,0 +1,35 @@
1
+ import { type PosCodeTable, type PosCutMode, type PosPaperSize, type QrCorrection, type QrSize } from '../printing/index.js';
2
+ import type { ReceiptLayout } from './layout.js';
3
+ /**
4
+ * Bruecke vom Layout-Modell zu ESC/POS-Bytes — der Bondrucker-Ausgabeweg.
5
+ *
6
+ * Hier, und nur hier, wird der Belegtext **druckbar gemacht**
7
+ * ([escPosPrintableText]): Bondrucker sprechen eine Ein-Byte-Codepage, ein
8
+ * „€" oder ein Emoji im Artikelnamen laesst die Kodierung werfen und den
9
+ * gesamten Ausdruck ausfallen. Das Layout selbst fuehrt weiterhin echten Text
10
+ * — auf dem Bildschirm soll „€" stehen und nicht „EUR".
11
+ *
12
+ * Ausgenommen ist der QR-Inhalt: er ist maschinenlesbar (RKSV) und wird
13
+ * unveraendert uebergeben. Eine Zeichenersetzung machte den Code ungueltig;
14
+ * ein unerwartetes Zeichen darin soll darum auffallen und nicht still
15
+ * verfaelscht werden.
16
+ */
17
+ export interface EscPosLayoutOptions {
18
+ /** Papierbreite; Vorgabe ist die des Layouts (dessen Spaltenbreiten daran haengen). */
19
+ paperSize?: PosPaperSize;
20
+ /** Codepage des Druckers, Vorgabe `CP1252`; `null` laesst die des Geraets stehen. */
21
+ codeTable?: PosCodeTable | null;
22
+ /** Papierschnitt am Ende: `true` (voll), `'partial'` oder `false`. Vorgabe `true`. */
23
+ cut?: boolean | PosCutMode;
24
+ /** Modulgroesse des QR-Codes. */
25
+ qrSize?: QrSize;
26
+ /** Fehlerkorrekturstufe des QR-Codes. */
27
+ qrCorrection?: QrCorrection;
28
+ }
29
+ /**
30
+ * Bytes fuer den Bondrucker -- **aus dem Zeichenraster** ([renderReceiptGrid]):
31
+ * jede Rasterzeile geht als fertige, exakt N Zeichen breite Textzeile raus.
32
+ * Keine eigene Spaltenrechnung, keine `ESC $`-Positionierung: was das Raster
33
+ * zeigt, druckt der Drucker (Monospace, Font A: 32/48 Zeichen).
34
+ */
35
+ export declare function escPosLayoutBytes(layout: ReceiptLayout, options?: EscPosLayoutOptions): Uint8Array;
@@ -0,0 +1,64 @@
1
+ import { createEscPosDocument, escPosBytes, escPosCut, escPosFeed, escPosPrintableText, escPosQrCode, escPosReset, escPosText, } from '../printing/index.js';
2
+ import { renderReceiptGrid, ZEICHEN_JE_PAPIER } from './grid.js';
3
+ /**
4
+ * Druckbar gemachtes Layout: Texte durch [escPosPrintableText] (Codepage,
5
+ * "EUR" statt "€", Striche), damit das Raster mit den Zeichen rechnet, die
6
+ * wirklich aufs Papier gehen. Der QR-Inhalt bleibt unveraendert.
7
+ */
8
+ function druckbaresLayout(layout) {
9
+ return {
10
+ ...layout,
11
+ lines: layout.lines.map((z) => {
12
+ switch (z.kind) {
13
+ case 'text': return { ...z, text: escPosPrintableText(z.text) };
14
+ case 'banner': return { ...z, text: escPosPrintableText(z.text) };
15
+ case 'columns': return { ...z, columns: z.columns.map((c) => ({ ...c, text: escPosPrintableText(c.text) })) };
16
+ case 'rule': return { ...z, char: escPosPrintableText(z.char) || '-' };
17
+ default: return z;
18
+ }
19
+ }),
20
+ };
21
+ }
22
+ /**
23
+ * Bytes fuer den Bondrucker -- **aus dem Zeichenraster** ([renderReceiptGrid]):
24
+ * jede Rasterzeile geht als fertige, exakt N Zeichen breite Textzeile raus.
25
+ * Keine eigene Spaltenrechnung, keine `ESC $`-Positionierung: was das Raster
26
+ * zeigt, druckt der Drucker (Monospace, Font A: 32/48 Zeichen).
27
+ */
28
+ export function escPosLayoutBytes(layout, options = {}) {
29
+ const paperSize = options.paperSize ?? layout.paperSize;
30
+ const dokumentOptionen = { paperSize };
31
+ if (options.codeTable !== undefined) {
32
+ dokumentOptionen.codeTable = options.codeTable;
33
+ }
34
+ const doc = createEscPosDocument(dokumentOptionen);
35
+ escPosReset(doc);
36
+ const qrOptionen = { align: 'center' };
37
+ if (options.qrSize !== undefined)
38
+ qrOptionen.size = options.qrSize;
39
+ if (options.qrCorrection !== undefined)
40
+ qrOptionen.correction = options.qrCorrection;
41
+ const grid = renderReceiptGrid(druckbaresLayout(layout), { zeichen: ZEICHEN_JE_PAPIER[paperSize] });
42
+ for (const zeile of grid.lines) {
43
+ switch (zeile.kind) {
44
+ case 'space':
45
+ escPosFeed(doc, 1);
46
+ break;
47
+ case 'qr':
48
+ escPosQrCode(doc, zeile.qr ?? '', qrOptionen);
49
+ break;
50
+ case 'banner':
51
+ // Belegart/Warnung: fett, doppelte Hoehe; Warnungen zusaetzlich invers.
52
+ // Der Text ist bereits zentriert aufgefuellt (Raster).
53
+ escPosText(doc, zeile.text.trimEnd(), { styles: { align: 'left', bold: true, height: 2, reverse: zeile.ton === 'warnung' } });
54
+ break;
55
+ default:
56
+ escPosText(doc, zeile.text.trimEnd(), { styles: { align: 'left', bold: zeile.bold } });
57
+ break;
58
+ }
59
+ }
60
+ if (options.cut !== false) {
61
+ escPosCut(doc, options.cut === 'partial' ? 'partial' : 'full');
62
+ }
63
+ return escPosBytes(doc);
64
+ }
@@ -0,0 +1,180 @@
1
+ import { type Receipt, type ReceiptCompany } from '../models/index.js';
2
+ import type { PosPaperSize } from '../printing/escpos.js';
3
+ /**
4
+ * Beleg-Layout — der Bauplan eines Kasseneck-Belegs als reines Datenmodell.
5
+ *
6
+ * Aufbau und Reihenfolge stammen aus dem Flutter-Vorbild
7
+ * `kasseneck_api/lib/models/print_paper.dart` (`setKeckReceipt`). Der
8
+ * Unterschied: dort entstehen unmittelbar Druckerbytes, hier entsteht **eine
9
+ * Folge von Zeilen**. Wer sie zeichnet, entscheidet der Aufrufer — der
10
+ * React-Adapter (`@kreiseck/kasseneck-api/react`) fuer den Bildschirm,
11
+ * [escPosLayoutBytes] (`./layout-escpos.js`) fuer den Bondrucker, ein
12
+ * PDF-Erzeuger im Backend. Damit steht die Reihenfolge der Belegangaben genau
13
+ * einmal da und nicht je Ausgabeweg erneut.
14
+ *
15
+ * Kein Framework, keine Druckerabhaengigkeit, keine Bildverarbeitung: das
16
+ * Modell laeuft unveraendert im Browser und in Node.
17
+ *
18
+ * **Der Text im Modell ist echter Text.** Ein Euro-Zeichen ist hier ein „€",
19
+ * kein „EUR". Bondrucker koennen es nicht darstellen; die Ersetzung sitzt
20
+ * deshalb an genau einer Stelle in der ESC/POS-Bruecke und nicht hier — sonst
21
+ * stuende auch auf dem Bildschirm „EUR".
22
+ *
23
+ * Bewusst **nicht** enthalten: Firmenlogo und Rasterbilder (brauchen
24
+ * Bildverarbeitung, die im Browser anders aussieht als in Node), PDF-Erzeugung,
25
+ * Druckeransteuerung und die anbieterspezifischen Kartenzahlungsbloecke des
26
+ * Vorbilds (GP Tom, Hobex, SumUp, myPOS, Stripe).
27
+ */
28
+ /** Ausrichtung einer Zeile bzw. einer Spalte. */
29
+ export type LayoutAlign = 'left' | 'center' | 'right';
30
+ /** Eine Spalte einer Spaltenzeile; `width` ist ein Zwoelftel-Anteil (1..12). */
31
+ export interface LayoutColumn {
32
+ text: string;
33
+ width: number;
34
+ align: LayoutAlign;
35
+ }
36
+ /** Eine Textzeile ueber die volle Breite. */
37
+ export interface LayoutTextLine {
38
+ kind: 'text';
39
+ text: string;
40
+ align: LayoutAlign;
41
+ bold: boolean;
42
+ }
43
+ /** Eine Zeile aus mehreren Spalten; die Breiten ergeben zusammen 12. */
44
+ export interface LayoutColumnsLine {
45
+ kind: 'columns';
46
+ columns: LayoutColumn[];
47
+ }
48
+ /** Eine durchgehende Trennlinie aus [char]. */
49
+ export interface LayoutRuleLine {
50
+ kind: 'rule';
51
+ char: string;
52
+ }
53
+ /** Leerraum von [lines] Zeilen. */
54
+ export interface LayoutSpaceLine {
55
+ kind: 'space';
56
+ lines: number;
57
+ }
58
+ /** Der maschinenlesbare RKSV-Code. [data] ist die Nutzlast, unveraendert. */
59
+ export interface LayoutQrLine {
60
+ kind: 'qr';
61
+ data: string;
62
+ }
63
+ /**
64
+ * Hervorgehobene Zeile (Belegart, Testhinweise): fett, zentriert, vom
65
+ * Zeichner sichtbar abgesetzt (Rahmen, invers oder Groesse). Der Text ist
66
+ * bereits fertig (RKSV § 11 Abs. 3: Trainings- und Stornobuchungen sind
67
+ * ausdruecklich als solche zu bezeichnen).
68
+ */
69
+ export interface LayoutBannerLine {
70
+ kind: 'banner';
71
+ text: string;
72
+ /** `warnung` fuer Testkasse/Testsignatur (nicht gueltiger Beleg), sonst `belegart`. */
73
+ ton: 'belegart' | 'warnung';
74
+ }
75
+ export type LayoutLine = LayoutTextLine | LayoutColumnsLine | LayoutRuleLine | LayoutSpaceLine | LayoutQrLine | LayoutBannerLine;
76
+ /**
77
+ * Version des Layout-Regelwerks. Alte Belege werden mit ihrer gespeicherten
78
+ * Version gesetzt.
79
+ * - 1: Nullbeleg reduziert mit Summenzeile „Betrag: 0,00 €“.
80
+ * - 2: Nullbeleg als Pruefbeleg mit Block „Prüfangaben“ (Barumsatz, Signatur,
81
+ * Signaturkarte, Zertifizierungsdienst, Registrierdaten); reduziert nur,
82
+ * wenn alle Betraege wirklich 0 sind. Vollbelege unveraendert.
83
+ */
84
+ export type LayoutRegelwerk = 1 | 2;
85
+ export declare const AKTUELLES_REGELWERK: LayoutRegelwerk;
86
+ /**
87
+ * Registrierdaten fuer den Block „Prüfangaben“ auf Nullbelegen (Regelwerk 2).
88
+ * Kennt sie nur das Backend (FinanzOnline-Registrierung der Signaturkarte und
89
+ * der Kasse); fehlen sie, entfallen die Zeilen. Datum als „YYYY-MM-DD“ oder
90
+ * ISO-Zeitstempel (Wiener Kalendertag).
91
+ */
92
+ export interface Pruefangaben {
93
+ karteRegistriertAm?: string | null;
94
+ kasseRegistriertAm?: string | null;
95
+ }
96
+ /** Der fertige Bauplan eines Belegs. */
97
+ export interface ReceiptLayout {
98
+ lines: LayoutLine[];
99
+ /** Papierbreite, nach der die Spaltenbreiten gewaehlt wurden. */
100
+ paperSize: PosPaperSize;
101
+ /** Regelwerk, nach dem gesetzt wurde. */
102
+ regelwerk: LayoutRegelwerk;
103
+ }
104
+ export interface BuildReceiptLayoutOptions {
105
+ /**
106
+ * Papierbreite; sie bestimmt — wie im Vorbild — allein die Spaltenbreiten
107
+ * der USt-Tabelle. Vorgabe `mm58`.
108
+ */
109
+ paperSize?: PosPaperSize;
110
+ /** Layout-Regelwerk (Vorgabe: aktuelles). Unbekannt -> Fehler, nie stumm anders setzen. */
111
+ regelwerk?: LayoutRegelwerk;
112
+ /** Beleg einer Testumgebung: Rahmen „TESTKASSE — kein gültiger Beleg“ oben und unten. */
113
+ testKasse?: boolean;
114
+ /**
115
+ * Produktionskonto hat mit einer Test-Signatureinheit signiert: Rahmen
116
+ * „TESTSIGNATUR — kein gültiger Beleg“. Der Aufrufer entscheidet (er kennt
117
+ * das Konto); [receiptSignatureIsTest] sagt nur, OB die Signatur eine Testsignatur ist.
118
+ */
119
+ testSignatur?: boolean;
120
+ /** Registrierdaten fuer den Block „Prüfangaben“ (nur Nullbelege, Regelwerk 2). */
121
+ pruefangaben?: Pruefangaben | null;
122
+ }
123
+ /**
124
+ * Cent-Betrag als Anzeigetext: `1234` -> `"12,34"`. Die **einzige** Stelle, an
125
+ * der aus Cent eine Zeichenkette wird. Erwartet ganze Cent (Geld wird in
126
+ * diesem Paket ausnahmslos ganzzahlig gerechnet).
127
+ */
128
+ export declare function formatCents(cents: number): string;
129
+ /**
130
+ * Hinweis auf die Steuerbefreiung, den ein Kleinunternehmerbeleg tragen muss —
131
+ * ohne ihn stuende in der USt-Tabelle „D 0 %" ohne jede Begruendung, und ab
132
+ * 400 € greift § 11 UStG voll.
133
+ *
134
+ * Wortlaut **woertlich** aus dem Backend (`INVOICE_TAX_NOTE.smallBusiness` in
135
+ * functions/index.js), damit auf Beleg und Rechnung derselbe Satz steht. Er
136
+ * traegt einen Gedankenstrich (U+2013), kein Bindestrich; der Bondrucker
137
+ * bekommt ihn ueber die Ersetzung der ESC/POS-Bruecke.
138
+ *
139
+ * Weder `print_paper.dart` noch das Beleg-PDF des Backends drucken den Hinweis
140
+ * heute — hier liegt das Kennzeichen vor, also steht er hier.
141
+ *
142
+ * Der **Name** ist englisch wie die uebrige Oberflaeche (`DEFAULT_BASE_URL`,
143
+ * `formatCents`, `buildReceiptLayout`); der **Wortlaut** ist selbstverstaendlich
144
+ * deutsch — er steht so auf oesterreichischen Belegen.
145
+ */
146
+ export declare const SMALL_BUSINESS_NOTICE = "Umsatzsteuerbefreit \u2013 Kleinunternehmer gem\u00E4\u00DF \u00A7 6 Abs. 1 Z 27 UStG.";
147
+ /** Wurde der Beleg ohne funktionierende Signatureinheit ausgestellt? */
148
+ export declare function receiptSignatureFailed(receipt: Receipt): boolean;
149
+ /**
150
+ * Traegt der Beleg eine **Test**-Signatur? Erkannt am ZDA-Kennzeichen `AT100`
151
+ * im maschinenlesbaren Code (`_R1-AT100_...`) — der Testpfad der Testumgebungen.
152
+ * Ob das ein Problem ist, weiss nur der Aufrufer (Testkonto: normal;
153
+ * Produktionskonto: „TESTSIGNATUR“-Warnung).
154
+ */
155
+ export declare function receiptSignatureIsTest(receipt: Pick<Receipt, 'qr'>): boolean;
156
+ /** Ist das ein Nullbeleg (Start-, Monats-, Jahres-, Schluss-, Pruefbeleg)? */
157
+ export declare function receiptIsZero(receipt: Receipt): boolean;
158
+ /**
159
+ * Sind alle Betraege des Belegs wirklich 0? (Keine Positionen mit Wert, keine
160
+ * Gutscheine.) Ein Nullbeleg, der das nicht erfuellt, ist ein Datenfehler --
161
+ * Regelwerk 2 setzt ihn dann als normalen Beleg.
162
+ */
163
+ export declare function receiptAmountsAreZero(receipt: Receipt): boolean;
164
+ /**
165
+ * Zertifizierungsdienst aus der QR-Kennung `_R1-<ZDA>_` (RKSV-Detailspezifikation:
166
+ * AT0 geschlossenes System, AT1 A-Trust, AT2 GlobalTrust, AT3 PrimeSign,
167
+ * AT100 Testsignatur). Unbekannte Kennung: nur die Kennung.
168
+ */
169
+ export declare function receiptZdaText(qr: string): string | null;
170
+ /**
171
+ * Kleinunternehmer (§ 6 Abs. 1 Z 27 UStG, unechte Befreiung): auf dem Beleg
172
+ * darf keine USt stehen -- jede Position 0 %. Sagt, ob der Beleg dazu passt;
173
+ * das Backend weist Widersprueche beim Ausstellen ab, hier ist es die Probe.
174
+ */
175
+ export declare function receiptIsSmallBusinessConsistent(receipt: Receipt): boolean;
176
+ /**
177
+ * Baut das Layout eines Belegs. Reihenfolge und Spaltenbreiten folgen
178
+ * `print_paper.dart` (`setKeckReceipt`).
179
+ */
180
+ export declare function buildReceiptLayout(receipt: Receipt, company: ReceiptCompany, options?: BuildReceiptLayoutOptions): ReceiptLayout;