@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,438 @@
1
+ import { ReceiptType, KeckPaymentMethod, CreditCardProvider, VoucherAction, VoucherType, } from '../enums/index.js';
2
+ import { fromReceiptCompanyPayload, fromReceiptPayload, toReceiptItemPayload, toVoucherPayload, receiptItemIsValid, voucherIsValid, fromReceiptSummaryPayload, isCancellationReason, } from '../models/index.js';
3
+ import { parseServerTimeStamp, toViennaWallClock } from '../vienna-time.js';
4
+ import { euroToCents } from '../money.js';
5
+ import { KasseneckValidationError } from './errors.js';
6
+ /**
7
+ * Gemeinsame Umsetzung aller Belegarten (Zwilling von `_createReceipt`).
8
+ * Bewusst **nicht** Teil der Paketoberflaeche: der Belegtyp gehoert nicht in
9
+ * die Hand des Aufrufers, sondern zu einem der benannten Aufrufe darunter.
10
+ */
11
+ export async function createReceipt(rufen, options) {
12
+ return belegAusHuelle(await rufen('createReceipt', createReceiptParams(options)), 'createReceipt');
13
+ }
14
+ /** Wie [createReceipt], liest aus derselben Antwort zusaetzlich die Firmendaten. */
15
+ async function createReceiptWithCompany(rufen, options) {
16
+ return belegMitFirmaAusHuelle(await rufen('createReceipt', createReceiptParams(options)), 'createReceipt');
17
+ }
18
+ /**
19
+ * Baut die Nutzlast von `createReceipt` und prueft die Eingabe. Wirft, bevor
20
+ * irgendetwas rausgeht — ein Beleg ist nicht folgenlos wiederholbar.
21
+ */
22
+ function createReceiptParams(options) {
23
+ const typ = belegtyp(options.receiptType);
24
+ const { items, vouchers } = options;
25
+ if (typ.needsItems) {
26
+ // Ein reiner Gutscheinverkauf ist ein Umsatz ohne Positionen — deshalb
27
+ // zaehlt er hier wie eine Position (wie im Flutter-Vorbild).
28
+ const hatVerkaufsgutschein = vouchers?.some((v) => v.action === VoucherAction.sell) ?? false;
29
+ if ((items == null || items.length === 0) && !hatVerkaufsgutschein) {
30
+ throw eingabefehler(`Positionen sind Pflicht bei receiptType "${typ.value}" und duerfen nicht leer sein.`);
31
+ }
32
+ if (items?.some((item) => !receiptItemIsValid(item)) ?? false) {
33
+ throw eingabefehler('Ungueltige Position uebergeben.');
34
+ }
35
+ }
36
+ const params = { receiptType: typ.value };
37
+ if (vouchers != null && vouchers.length > 0) {
38
+ if (!typ.allowsVouchers) {
39
+ throw eingabefehler(`Gutscheine sind nicht erlaubt bei receiptType "${typ.value}".`);
40
+ }
41
+ if (vouchers.some((voucher) => !voucherIsValid(voucher))) {
42
+ throw eingabefehler('Ungueltiger Gutschein uebergeben.');
43
+ }
44
+ const kombinationsfehler = checkVoucherCombinationError(vouchers, items ?? []);
45
+ if (kombinationsfehler != null) {
46
+ throw eingabefehler(kombinationsfehler);
47
+ }
48
+ params['vouchers'] = alsNutzlast(vouchers, toVoucherPayload);
49
+ }
50
+ if (items != null && items.length > 0) {
51
+ params['items'] = alsNutzlast(items, toReceiptItemPayload);
52
+ }
53
+ // Vom Aufrufer kommt sie geprueft, vom Server roh — siehe die beiden Felder
54
+ // in [CreateReceiptOptions]. Die Typpruefung allein reicht dafuer nicht: ein
55
+ // Verbraucher ohne Typen faellt durch dieses Netz, und ein Tippfehler in der
56
+ // Zahlungsart faellt sonst erst am Server auf.
57
+ const zahlungsart = options.paymentMethod != null ? gepruefteZahlungsart(options.paymentMethod) : options.paymentMethodFromServer;
58
+ if (zahlungsart != null) {
59
+ params['paymentMethod'] = zahlungsart;
60
+ const anbieter = options.creditCardProvider ?? CreditCardProvider.custom;
61
+ if (zahlungsart === KeckPaymentMethod.creditCard.value) {
62
+ if (options.cardPaymentId != null) {
63
+ params['cardPaymentId'] = options.cardPaymentId;
64
+ // Der Kartenanbieter kommt dagegen vom Aufrufer, nicht vom Server —
65
+ // hier bleibt der Schreibpfad streng.
66
+ params['creditCardProvider'] = kartenanbieter(anbieter);
67
+ // Bewusst auch als `null`, wenn der Anbieter keine Rohdaten liefert:
68
+ // das Feld gehoert zur Kartenzahlung und das Backend nimmt null an.
69
+ params['cardPaymentData'] = options.cardPaymentData ?? null;
70
+ }
71
+ else if (anbieter !== CreditCardProvider.custom) {
72
+ throw eingabefehler(`cardPaymentId ist Pflicht bei creditCardProvider "${anbieter}".`);
73
+ }
74
+ }
75
+ }
76
+ if (options.customProjectId != null) {
77
+ params['customProjectId'] = options.customProjectId;
78
+ }
79
+ if (options.customerDetails != null) {
80
+ params['customerDetails'] = options.customerDetails.join('\n');
81
+ }
82
+ if (options.legalMessage != null) {
83
+ params['legalMessage'] = options.legalMessage.join('\n');
84
+ }
85
+ return params;
86
+ }
87
+ /** Normalbeleg (Verkauf) nach RKSV. */
88
+ export function sellReceipt(rufen, options) {
89
+ return createReceipt(rufen, { ...options, receiptType: ReceiptType.standard });
90
+ }
91
+ /**
92
+ * Normalbeleg wie [sellReceipt], liefert zusaetzlich die Firmen-/Druckdaten
93
+ * aus derselben Antwort — alles, was ein Belegdruck braucht, in einem Aufruf.
94
+ */
95
+ export function sellReceiptWithCompany(rufen, options) {
96
+ return createReceiptWithCompany(rufen, { ...options, receiptType: ReceiptType.standard });
97
+ }
98
+ const NOTE_MAX = 200;
99
+ /**
100
+ * Storno-Beleg zu einem bestehenden Beleg — voll oder in Teilen. Prueft die
101
+ * Eingabe, bevor etwas hinausgeht; der Server haelt die Restmengen und die
102
+ * Reichweite des Rechts (eigene/alle) und antwortet mit dem fertigen,
103
+ * signierten Storno-Beleg. Gutscheine des Originals wandern nicht mit.
104
+ */
105
+ export async function cancelReceipt(rufen, options) {
106
+ const cashregisterId = options.receipt?.cashregisterId ?? options.cashregisterId;
107
+ const originalReceiptId = options.receipt?.receiptId ?? options.originalReceiptId;
108
+ if (typeof cashregisterId !== 'string' || cashregisterId.trim() === '') {
109
+ throw new KasseneckValidationError('cancelReceipt', 'cashregisterId fehlt', 'request');
110
+ }
111
+ if (typeof originalReceiptId !== 'string' || originalReceiptId.trim() === '') {
112
+ throw new KasseneckValidationError('cancelReceipt', 'originalReceiptId fehlt', 'request');
113
+ }
114
+ if (!isCancellationReason(options.reason)) {
115
+ throw new KasseneckValidationError('cancelReceipt', 'Storno-Grund fehlt oder ist unbekannt', 'request');
116
+ }
117
+ if (options.items !== undefined) {
118
+ if (!Array.isArray(options.items) || options.items.length === 0) {
119
+ throw new KasseneckValidationError('cancelReceipt', 'items muss eine nicht leere Liste sein', 'request');
120
+ }
121
+ for (const pos of options.items) {
122
+ if (!Number.isInteger(pos.index) || pos.index < 0 || !Number.isInteger(pos.quantity) || pos.quantity < 1) {
123
+ throw new KasseneckValidationError('cancelReceipt', 'Storno-Menge muss eine ganze Zahl >= 1 sein', 'request');
124
+ }
125
+ }
126
+ }
127
+ if (options.note !== undefined && options.note.length > NOTE_MAX) {
128
+ throw new KasseneckValidationError('cancelReceipt', `Anmerkung ist zu lang (hoechstens ${NOTE_MAX} Zeichen)`, 'request');
129
+ }
130
+ const params = { cashregisterId, originalReceiptId, reason: options.reason };
131
+ if (options.items !== undefined)
132
+ params.items = options.items.map((p) => ({ index: p.index, quantity: p.quantity }));
133
+ if (options.note !== undefined && options.note !== '')
134
+ params.note = options.note;
135
+ if (options.paymentMethod != null)
136
+ params.paymentMethod = gepruefteZahlungsart(options.paymentMethod);
137
+ const daten = await rufen('cancelReceipt', params);
138
+ const receipt = belegAusHuelle(daten, 'cancelReceipt');
139
+ const huelle = daten;
140
+ const bezug = huelle.cancellationOf;
141
+ if (bezug == null || typeof bezug.receiptId !== 'string') {
142
+ throw antwortfehler('cancelReceipt', 'Antwort enthaelt keinen Bezug (data.cancellationOf fehlt)');
143
+ }
144
+ if (!Array.isArray(huelle.remaining) || !huelle.remaining.every((n) => Number.isInteger(n))) {
145
+ throw antwortfehler('cancelReceipt', 'Antwort enthaelt keine Restmengen (data.remaining fehlt)');
146
+ }
147
+ return {
148
+ receipt,
149
+ cancellationOf: { receiptId: bezug.receiptId, fullReceiptId: typeof bezug.fullReceiptId === 'string' ? bezug.fullReceiptId : null },
150
+ remaining: huelle.remaining,
151
+ };
152
+ }
153
+ /**
154
+ * Stornobeleg aus frei uebergebenen Positionen — fuer den Fall, dass der
155
+ * Originalbeleg nicht als Objekt vorliegt. Die Positionen gehen **unveraendert**
156
+ * hinaus; das Vorzeichen setzt der Aufrufer.
157
+ */
158
+ export function createCancelReceipt(rufen, options) {
159
+ return createReceipt(rufen, { ...options, receiptType: ReceiptType.cancellation });
160
+ }
161
+ /** Nullbeleg (RKSV-Pruefbeleg) — ohne Positionen und ohne Zahlungsart. */
162
+ export function zeroReceipt(rufen) {
163
+ return createReceipt(rufen, { receiptType: ReceiptType.zero });
164
+ }
165
+ /**
166
+ * Belege einer Kasse auflisten — die Grundlage jeder Belegliste in der
167
+ * Browser-Kasse (Nachdruck, Storno, Tagesuebersicht).
168
+ *
169
+ * Die Eintraege sind **Zusammenfassungen**, keine vollstaendigen Belege (siehe
170
+ * [ReceiptSummary]); fuer Nachdruck oder Storno gehoert der Beleg ueber
171
+ * [getReceipt] bzw. [getReceiptWithCompany] einzeln geholt.
172
+ *
173
+ * **Anmeldeweg:** Der Endpunkt laeuft im Backend unter
174
+ * `checkRequest(req, 'customer', …, {allowRegisterUser: true})`, der Bearer
175
+ * muss also ein Firebase-ID-Token sein — mit `apiKeyAuth` ist er nicht
176
+ * erreichbar. Ausserdem prueft das Backend die Kassenzuweisung hier im Rumpf
177
+ * (der Endpunkt laeuft mit `checkCashRegister: false`), ein Kassen-Benutzer
178
+ * bekommt also nur die ihm zugewiesenen Kassen.
179
+ */
180
+ export async function listMyReceipts(rufen, options) {
181
+ if (typeof options.cashregisterId !== 'string' || options.cashregisterId.trim() === '') {
182
+ throw new KasseneckValidationError('listMyReceipts', 'cashregisterId fehlt', 'request');
183
+ }
184
+ if (options.limit !== undefined && (!Number.isInteger(options.limit) || options.limit < 1)) {
185
+ throw new KasseneckValidationError('listMyReceipts', `limit muss eine ganze Zahl ab 1 sein, war "${options.limit}"`, 'request');
186
+ }
187
+ for (const feld of ['from', 'to']) {
188
+ const wert = options[feld];
189
+ if (wert !== undefined && !/^\d{4}-\d{2}-\d{2}/.test(wert)) {
190
+ throw new KasseneckValidationError('listMyReceipts', `${feld} muss mit YYYY-MM-DD beginnen, war "${wert}"`, 'request');
191
+ }
192
+ }
193
+ const daten = await rufen('listMyReceipts', {
194
+ cashregisterid: options.cashregisterId,
195
+ limit: options.limit,
196
+ ...(options.from !== undefined ? { from: options.from } : {}),
197
+ ...(options.to !== undefined ? { to: options.to } : {}),
198
+ });
199
+ const liste = daten?.receipts;
200
+ if (!Array.isArray(liste)) {
201
+ throw antwortfehler('listMyReceipts', 'Antwort enthaelt keine Belegliste (data.receipts fehlt)');
202
+ }
203
+ return {
204
+ receipts: liste.map((eintrag) => fromReceiptSummaryPayload((typeof eintrag === 'object' && eintrag !== null ? eintrag : {}))),
205
+ stats: kennzahlen(daten?.stats),
206
+ };
207
+ }
208
+ /**
209
+ * Kennzahlen aus der Antwort. Sie duerfen Luecken haben, ohne die Belegliste
210
+ * unbrauchbar zu machen — eine fehlende Wochenreihe ist kein Grund, dem
211
+ * Kassier die Belege vorzuenthalten.
212
+ */
213
+ function kennzahlen(roh) {
214
+ const quelle = (typeof roh === 'object' && roh !== null ? roh : {});
215
+ const tage = Array.isArray(quelle.days) ? quelle.days : [];
216
+ return {
217
+ today: {
218
+ revenueCents: euroToCents(quelle.today?.umsatz),
219
+ count: typeof quelle.today?.count === 'number' ? quelle.today.count : 0,
220
+ },
221
+ trendPercent: typeof quelle.trendPct === 'number' ? quelle.trendPct : null,
222
+ days: tage.map((tag) => {
223
+ const eintrag = (typeof tag === 'object' && tag !== null ? tag : {});
224
+ return {
225
+ date: typeof eintrag.date === 'string' ? eintrag.date : '',
226
+ revenueCents: euroToCents(eintrag.umsatz),
227
+ };
228
+ }),
229
+ };
230
+ }
231
+ /** Einzelnen Beleg der angemeldeten Kasse holen. */
232
+ export async function getReceipt(rufen, receiptId) {
233
+ return belegAusHuelle(await rufen('getReceipt', { receiptId }), 'getReceipt');
234
+ }
235
+ /**
236
+ * Wie [getReceipt], liefert zusaetzlich die Firmen-/Druckdaten aus derselben
237
+ * Antwort (Firma, Anschrift, Steuernummer, UID, Fusszeilen, Logo-Adresse,
238
+ * Kleinunternehmer-Kennzeichen) — die Angaben, die ein Beleg im Kopf und Fuss
239
+ * traegt (siehe models/receipt-company.ts).
240
+ */
241
+ export async function getReceiptWithCompany(rufen, receiptId) {
242
+ return belegMitFirmaAusHuelle(await rufen('getReceipt', { receiptId }), 'getReceipt');
243
+ }
244
+ /**
245
+ * Verschluesselte Volltext-Belegnummer erzeugen — der Bezeichner, unter dem der
246
+ * Beleg oeffentlich abrufbar ist (Beleg-Download, Pruefportal).
247
+ */
248
+ export async function generateFullReceiptId(rufen, receiptId) {
249
+ const daten = await rufen('generateFullReceiptId', { receiptId });
250
+ const id = daten?.fullReceiptId;
251
+ if (typeof id !== 'string') {
252
+ throw antwortfehler('generateFullReceiptId', 'Antwort enthaelt keine fullReceiptId');
253
+ }
254
+ return id;
255
+ }
256
+ /**
257
+ * Berichtsmonat des allerersten Belegs dieser Kasse — die untere Grenze aller
258
+ * Monatsberichte.
259
+ *
260
+ * **Nicht fuer den Kassen-Benutzer-Weg (`registerUserAuth`):** dieser Endpunkt
261
+ * fuehrt kein `allowRegisterUser`, das Backend weist die Browser-Kasse hier ab
262
+ * (siehe Modulkommentar oben). Mit `apiKeyAuth` ist er offen.
263
+ */
264
+ export async function getFirstReceiptDate(rufen) {
265
+ const roh = await rufen('getFirstReceiptDate');
266
+ if (typeof roh !== 'string') {
267
+ throw antwortfehler('getFirstReceiptDate', 'Antwort enthaelt keinen Zeitstempel');
268
+ }
269
+ // Ueber die Wiener Wanduhrzeit statt ueber getMonth(): der erste Beleg eines
270
+ // Monats liegt gern kurz nach Mitternacht, und der eingebaute Monat waere der
271
+ // des ausfuehrenden Rechners (siehe vienna-time.ts).
272
+ //
273
+ // Die Deutung wirft ein gewoehnliches Error, wenn der Zeitstempel unlesbar
274
+ // ist. Das ist hier ein Antwortproblem und gehoert in die Fehler-Union, die
275
+ // dieser Endpunkt zusagt — sonst faellt der Aufrufer aus allen Waechtern.
276
+ try {
277
+ const wanduhr = toViennaWallClock(parseServerTimeStamp(roh));
278
+ return { month: wanduhr.month, year: wanduhr.year };
279
+ }
280
+ catch {
281
+ // Der Zeitstempel selbst wandert NICHT in die Meldung: er kommt aus einer
282
+ // fremden Antwort, und was dort steht, ist nicht unsere Zusage.
283
+ throw antwortfehler('getFirstReceiptDate', 'Antwort enthaelt keinen lesbaren Zeitstempel');
284
+ }
285
+ }
286
+ /**
287
+ * Prueft die Gutschein-Kombination eines Belegs und liefert den ersten
288
+ * Regelverstoss als Text (oder `null`) — Zwilling von
289
+ * `checkVoucherCombinationError`. Bewusst als Rueckgabewert statt als Fehler:
290
+ * eine Kassenoberflaeche will das pruefen, **bevor** sie den Beleg abschickt.
291
+ */
292
+ export function checkVoucherCombinationError(vouchers, items) {
293
+ let einloesenWert = 0;
294
+ let verkaufenWert = 0;
295
+ let einloesenPromo = 0;
296
+ let verkaufenPromo = 0;
297
+ for (const voucher of vouchers) {
298
+ if (voucher.type === VoucherType.value && voucher.action === VoucherAction.redeem) {
299
+ einloesenWert++;
300
+ }
301
+ else if (voucher.type === VoucherType.value && voucher.action === VoucherAction.sell) {
302
+ verkaufenWert++;
303
+ }
304
+ else if (voucher.type === VoucherType.promo && voucher.action === VoucherAction.redeem) {
305
+ einloesenPromo++;
306
+ }
307
+ else if (voucher.type === VoucherType.promo && voucher.action === VoucherAction.sell) {
308
+ verkaufenPromo++;
309
+ }
310
+ }
311
+ const einloesenGesamt = einloesenWert + einloesenPromo;
312
+ const verkaufenGesamt = verkaufenWert + verkaufenPromo;
313
+ if (verkaufenPromo > 0) {
314
+ return 'Ungueltige Daten: Gutscheine mit type promo duerfen nicht verkauft werden';
315
+ }
316
+ if (einloesenPromo > 1) {
317
+ return 'Ungueltige Daten: Es darf nur ein Gutschein mit type promo eingeloest werden';
318
+ }
319
+ if (einloesenPromo > 0 && einloesenGesamt > 1) {
320
+ return 'Ungueltige Daten: Ein Gutschein mit type promo darf nicht mit anderen Gutscheinen kombiniert werden';
321
+ }
322
+ if (einloesenPromo > 0 && verkaufenGesamt > 0) {
323
+ return 'Ungueltige Daten: Mit einem Gutschein mit type promo duerfen nicht andere Gutscheine verkauft werden';
324
+ }
325
+ if (einloesenGesamt > 0 && items.length === 0) {
326
+ return 'Ungueltige Daten: Gutscheine mit action redeem benoetigen mindestens ein item';
327
+ }
328
+ return null;
329
+ }
330
+ /**
331
+ * Belegtyp aufloesen. Anders als bei der Zahlungsart bleibt es hier streng:
332
+ * den Belegtyp setzt kein Aufrufer aus Serverdaten, er kommt aus einem der
333
+ * benannten Aufrufe — ein unbekannter Wert waere ein Programmierfehler.
334
+ */
335
+ function belegtyp(wert) {
336
+ if (typeof wert === 'object') {
337
+ return wert;
338
+ }
339
+ if (!Object.prototype.hasOwnProperty.call(ReceiptType, wert)) {
340
+ throw eingabefehler(`Belegtyp: unbekannter Schluessel "${wert}"`);
341
+ }
342
+ return ReceiptType[wert];
343
+ }
344
+ /**
345
+ * Wandelt Positionen/Gutscheine in ihre Nutzlast und faengt dabei die strengen
346
+ * Schreibpfad-Pruefungen der Modelle ab (unbekannter Steuersatz, unbekannte
347
+ * Gutschein-Aktion). Die Modelle werfen dort ein nacktes `Error`; hier soll
348
+ * nur die Fehler-Union des Pakets herauskommen, damit ein Verbraucher, der
349
+ * nach den Waechtern verzweigt, nicht im "unbekannt"-Zweig landet.
350
+ */
351
+ function alsNutzlast(werte, wandeln) {
352
+ try {
353
+ return werte.map(wandeln);
354
+ }
355
+ catch (ursache) {
356
+ // Die Meldungen der Modelle sind vom Paket formuliert und geheimnisfrei
357
+ // (sie nennen den unbekannten Steuersatz bzw. Schluessel, sonst nichts).
358
+ throw eingabefehler(ursache instanceof Error ? ursache.message : 'Ungueltige Nutzlast uebergeben.');
359
+ }
360
+ }
361
+ /** Zahlungsart des Aufrufers pruefen — unbekannt wirft, bevor etwas rausgeht. */
362
+ function gepruefteZahlungsart(wert) {
363
+ if (typeof wert === 'object') {
364
+ return wert.value;
365
+ }
366
+ if (!Object.prototype.hasOwnProperty.call(KeckPaymentMethod, wert)) {
367
+ throw eingabefehler(`Zahlungsart: unbekannter Schluessel "${wert}"`);
368
+ }
369
+ return KeckPaymentMethod[wert].value;
370
+ }
371
+ /** Kartenanbieter pruefen — er stammt vom Aufrufer, nicht aus Serverdaten. */
372
+ function kartenanbieter(wert) {
373
+ if (!Object.prototype.hasOwnProperty.call(CreditCardProvider, wert)) {
374
+ throw eingabefehler(`Kartenanbieter: unbekannter Schluessel "${wert}"`);
375
+ }
376
+ return wert;
377
+ }
378
+ /** Fehler in der Eingabe des Aufrufers — es geht keine Anfrage raus. */
379
+ function eingabefehler(grund) {
380
+ return new KasseneckValidationError('createReceipt', grund, 'request');
381
+ }
382
+ /** Die Antwort meldete Erfolg, trug aber nicht, was der Aufruf zusagt. */
383
+ function antwortfehler(functionName, grund) {
384
+ return new KasseneckValidationError(functionName, grund, 'response');
385
+ }
386
+ /**
387
+ * `createReceipt` und `getReceipt` liefern den Beleg unter `data.receipt`,
388
+ * daneben die Firmen-/Druckdaten (Firma, Anschrift, Fusszeilen). Diese Lesart
389
+ * nimmt nur den Beleg: die Druckdaten gehoeren nicht zum RKSV-Kernbeleg (siehe
390
+ * models/receipt.ts), und die bestehenden Aufrufe sollen ihre Zusage behalten.
391
+ * Wer beides braucht, nimmt [belegMitFirmaAusHuelle] ueber die
392
+ * `…WithCompany`-Varianten.
393
+ */
394
+ function belegAusHuelle(daten, functionName) {
395
+ const huelle = daten;
396
+ if (huelle == null || typeof huelle !== 'object' || huelle.receipt == null) {
397
+ throw antwortfehler(functionName, 'Antwort enthaelt keinen Beleg (data.receipt fehlt)');
398
+ }
399
+ const beleg = huelle.receipt;
400
+ if (typeof beleg !== 'object' || Array.isArray(beleg)) {
401
+ throw antwortfehler(functionName, 'Antwort enthaelt keinen Beleg (data.receipt ist kein Objekt)');
402
+ }
403
+ // Positionen und Gutscheine werden gleich mit `.map` gelesen. Eine Antwort,
404
+ // die dort etwas anderes als eine Liste fuehrt, ergab bis hierher einen
405
+ // nackten TypeError ("… .map is not a function") und fiel damit aus der
406
+ // Fehler-Union. Fehlend und `null` bleiben erlaubt: Nullbelege haben keine
407
+ // Positionen.
408
+ const roh = beleg;
409
+ for (const feld of ['items', 'vouchers']) {
410
+ const wert = roh[feld];
411
+ if (wert != null && !Array.isArray(wert)) {
412
+ throw antwortfehler(functionName, `Antwort enthaelt einen Beleg mit unbrauchbarem Feld "${feld}"`);
413
+ }
414
+ }
415
+ return fromReceiptPayload(beleg);
416
+ }
417
+ /**
418
+ * Beleg **und** Firmendaten aus derselben Huelle. Der Beleg entscheidet:
419
+ * fehlt er, ist die Antwort unbrauchbar. Die Firmendaten duerfen dagegen
420
+ * luecken haben — ein Kundendokument ohne gepflegte Fusszeile ist kein Grund,
421
+ * einen ausgestellten Beleg nicht anzuzeigen (siehe models/receipt-company.ts).
422
+ */
423
+ function belegMitFirmaAusHuelle(daten, functionName) {
424
+ const receipt = belegAusHuelle(daten, functionName);
425
+ const d = (daten ?? {});
426
+ const layout = d.layout && typeof d.layout === 'object' && Array.isArray(d.layout.lines) ? d.layout : null;
427
+ const pa = d.pruefangaben && typeof d.pruefangaben === 'object' ? d.pruefangaben : null;
428
+ const text = (v) => (typeof v === 'string' && v ? v : null);
429
+ return {
430
+ receipt,
431
+ company: fromReceiptCompanyPayload(daten),
432
+ testKasse: d.testKasse === true,
433
+ testSignatur: d.testSignatur === true,
434
+ kopfId: typeof d.kopfId === 'string' ? d.kopfId : null,
435
+ layout,
436
+ pruefangaben: pa ? { karteRegistriertAm: text(pa.karteRegistriertAm), kasseRegistriertAm: text(pa.kasseRegistriertAm) } : null,
437
+ };
438
+ }
@@ -0,0 +1,43 @@
1
+ import type { ReportMonth } from '../models/index.js';
2
+ import type { KasseneckBinaryTransport } from './transport.js';
3
+ /**
4
+ * Bericht-Downloads — Zwilling von `downloadDailyReport`/`downloadMonthlyReport`
5
+ * in kasseneck_api/lib/kasseneck_api.dart (Zeilen 113-128).
6
+ *
7
+ * **Beide liefern ein PDF, also Binaerdaten.** Das Flutter-Vorbild liest die
8
+ * Antwort als Zeichenkette und nimmt davon `codeUnits`; in JavaScript waere das
9
+ * schlicht falsch — `response.text()` deutet die Bytes als UTF-8 und ersetzt
10
+ * jedes Byte ueber 0x7F durch U+FFFD. Ein so "heruntergeladener" Tagesbericht
11
+ * liesse sich in keinem Betrachter oeffnen. Dieses Paket weicht daher bewusst
12
+ * ab: es liest `arrayBuffer()` und liefert `Uint8Array` (siehe
13
+ * [createBinaryTransport] in transport.ts).
14
+ *
15
+ * **Kassen-Benutzer-Weg (`registerUserAuth`, Browser-Kasse):** Keiner der
16
+ * beiden Download-Endpunkte setzt `allowRegisterUser`; sie funktionieren nur
17
+ * mit `apiKeyAuth`. Dieses Paket bildet das **nicht** nach; wer darf,
18
+ * entscheidet allein das Backend. Der Hinweis steht hier, damit ein Leser
19
+ * nicht raten muss.
20
+ */
21
+ /**
22
+ * Tagesbericht als PDF.
23
+ *
24
+ * Der Kalendertag wird nach **Wiener** Wanduhrzeit bestimmt, nicht nach der
25
+ * Zeitzone des ausfuehrenden Rechners: der Geschaeftstag ist ein
26
+ * oesterreichischer Kalenderwert. Ein Zeitpunkt vom 1. Maerz 00:30 Wiener Zeit
27
+ * gehoert in den Tagesbericht vom 1. Maerz — die eingebauten
28
+ * `getDate()`/`getMonth()` wuerden auf einer UTC-Maschine den Bericht des
29
+ * Vortags holen (das Dart-Vorbild nimmt hier die Geraetezeit, was auf einer
30
+ * oesterreichischen Kasse zufaellig stimmt).
31
+ */
32
+ export declare function downloadDailyReport(rufen: KasseneckBinaryTransport, date: Date): Promise<Uint8Array>;
33
+ /**
34
+ * Monatsbericht als PDF.
35
+ *
36
+ * **Der Endpunkt heisst `downloadReport`**, nicht `downloadMonthlyReport` —
37
+ * Methodenname und Endpunktname fallen hier auseinander (so im Dart-Vorbild und
38
+ * so im Backend, `report-endpoints.js`).
39
+ *
40
+ * `month` geht als **Zahl 1-12** raus (im Flutter-Paket `reportMonth.month.id`,
41
+ * wo `KeckMonth.january.id === 1` ist) — kein Name, kein nullbasierter Index.
42
+ */
43
+ export declare function downloadMonthlyReport(rufen: KasseneckBinaryTransport, reportMonth: ReportMonth): Promise<Uint8Array>;
@@ -0,0 +1,69 @@
1
+ import { toViennaWallClock } from '../vienna-time.js';
2
+ import { KasseneckValidationError } from './errors.js';
3
+ /**
4
+ * Bericht-Downloads — Zwilling von `downloadDailyReport`/`downloadMonthlyReport`
5
+ * in kasseneck_api/lib/kasseneck_api.dart (Zeilen 113-128).
6
+ *
7
+ * **Beide liefern ein PDF, also Binaerdaten.** Das Flutter-Vorbild liest die
8
+ * Antwort als Zeichenkette und nimmt davon `codeUnits`; in JavaScript waere das
9
+ * schlicht falsch — `response.text()` deutet die Bytes als UTF-8 und ersetzt
10
+ * jedes Byte ueber 0x7F durch U+FFFD. Ein so "heruntergeladener" Tagesbericht
11
+ * liesse sich in keinem Betrachter oeffnen. Dieses Paket weicht daher bewusst
12
+ * ab: es liest `arrayBuffer()` und liefert `Uint8Array` (siehe
13
+ * [createBinaryTransport] in transport.ts).
14
+ *
15
+ * **Kassen-Benutzer-Weg (`registerUserAuth`, Browser-Kasse):** Keiner der
16
+ * beiden Download-Endpunkte setzt `allowRegisterUser`; sie funktionieren nur
17
+ * mit `apiKeyAuth`. Dieses Paket bildet das **nicht** nach; wer darf,
18
+ * entscheidet allein das Backend. Der Hinweis steht hier, damit ein Leser
19
+ * nicht raten muss.
20
+ */
21
+ /**
22
+ * Tagesbericht als PDF.
23
+ *
24
+ * Der Kalendertag wird nach **Wiener** Wanduhrzeit bestimmt, nicht nach der
25
+ * Zeitzone des ausfuehrenden Rechners: der Geschaeftstag ist ein
26
+ * oesterreichischer Kalenderwert. Ein Zeitpunkt vom 1. Maerz 00:30 Wiener Zeit
27
+ * gehoert in den Tagesbericht vom 1. Maerz — die eingebauten
28
+ * `getDate()`/`getMonth()` wuerden auf einer UTC-Maschine den Bericht des
29
+ * Vortags holen (das Dart-Vorbild nimmt hier die Geraetezeit, was auf einer
30
+ * oesterreichischen Kasse zufaellig stimmt).
31
+ */
32
+ // `async`, damit auch die Eingabepruefung als abgelehntes Versprechen ankommt
33
+ // und nicht als synchroner Wurf am `await` des Aufrufers vorbei.
34
+ export async function downloadDailyReport(rufen, date) {
35
+ let wanduhr;
36
+ try {
37
+ wanduhr = toViennaWallClock(date);
38
+ }
39
+ catch {
40
+ // Ein Invalid Date ergaebe sonst `{year: null, month: null, day: null}` im
41
+ // Rumpf (JSON.stringify macht aus NaN null) und einen ratlosen Serverfehler.
42
+ throw eingabefehler('downloadDailyReport', 'Uebergebener Zeitpunkt ist unbrauchbar (Invalid Date)');
43
+ }
44
+ return rufen('downloadDailyReport', { year: wanduhr.year, month: wanduhr.month, day: wanduhr.day });
45
+ }
46
+ /**
47
+ * Monatsbericht als PDF.
48
+ *
49
+ * **Der Endpunkt heisst `downloadReport`**, nicht `downloadMonthlyReport` —
50
+ * Methodenname und Endpunktname fallen hier auseinander (so im Dart-Vorbild und
51
+ * so im Backend, `report-endpoints.js`).
52
+ *
53
+ * `month` geht als **Zahl 1-12** raus (im Flutter-Paket `reportMonth.month.id`,
54
+ * wo `KeckMonth.january.id === 1` ist) — kein Name, kein nullbasierter Index.
55
+ */
56
+ export async function downloadMonthlyReport(rufen, reportMonth) {
57
+ const { month, year } = reportMonth;
58
+ if (!Number.isInteger(month) || month < 1 || month > 12) {
59
+ throw eingabefehler('downloadReport', `Berichtsmonat: month muss 1-12 sein, war "${month}"`);
60
+ }
61
+ if (!Number.isInteger(year)) {
62
+ throw eingabefehler('downloadReport', `Berichtsmonat: year muss eine ganze Zahl sein, war "${year}"`);
63
+ }
64
+ return rufen('downloadReport', { month, year });
65
+ }
66
+ /** Fehler in der Eingabe des Aufrufers — es geht keine Anfrage raus. */
67
+ function eingabefehler(functionName, grund) {
68
+ return new KasseneckValidationError(functionName, grund, 'request');
69
+ }
@@ -0,0 +1,43 @@
1
+ import type { KasseneckTransport } from './transport.js';
2
+ /**
3
+ * Betriebsstatus von Kasse und Signatureinheit bei FinanzOnline — Zwilling von
4
+ * `getCashboxStatus`/`getSignatureStatus` in
5
+ * kasseneck_api/lib/kasseneck_api.dart (Zeilen 410-440).
6
+ *
7
+ * Beide laufen ueber den **einen** Backend-Endpunkt `financeWebService`, der
8
+ * seine Vorgangsart als `method` **neben** `params` im Rumpf erwartet (so das
9
+ * Dart-Vorbild `_financeWebServicePostRequest`, so die Auswertung `b.method` im
10
+ * Backend). Die Antwort ist die uebliche Erfolgshuelle; darin liegt die
11
+ * FinanzOnline-Meldung unter `data.rkdbMessage`.
12
+ *
13
+ * **Kassen-Benutzer-Weg (`registerUserAuth`, Browser-Kasse):**
14
+ * `financeWebService` setzt kein `allowRegisterUser`; beide Abfragen
15
+ * funktionieren nur mit `apiKeyAuth`. Dieses Paket bildet das **nicht** nach —
16
+ * wer darf, entscheidet allein das Backend.
17
+ */
18
+ /**
19
+ * Betriebsstatus, den FinanzOnline meldet. Die vier bekannten Werte sind
20
+ * benannt; ein noch unbekannter Wert kommt **unveraendert** durch (`string`),
21
+ * statt wie im Dart-Vorbild still zu `null` zu werden. Lesen ist in diesem
22
+ * Paket tolerant: "unbekannter Status" und "kein Status" duerfen fuer den
23
+ * Aufrufer nicht dasselbe sein, sonst meldet eine Kasse mit einem neuen
24
+ * FON-Status genauso wie eine ohne Antwort.
25
+ */
26
+ export type CashboxStatus = 'AKTIVIERT' | 'REGISTRIERT' | 'IN_BETRIEB' | 'AUSFALL' | (string & {});
27
+ /**
28
+ * Status der Signatureinheit. Wie [CashboxStatus], zusaetzlich der
29
+ * **abgeleitete** Wert `NOT_REGISTERED`: er ist kein FON-Status, sondern die
30
+ * Uebersetzung des Returncodes `B33` ("Signatureinheit nicht registriert").
31
+ */
32
+ export type SignatureStatus = CashboxStatus | 'NOT_REGISTERED';
33
+ /** Betriebsstatus der Kasse bei FinanzOnline. */
34
+ export declare function getCashboxStatus(rufen: KasseneckTransport): Promise<CashboxStatus>;
35
+ /**
36
+ * Status der Signatureinheit mit der Zertifikatsseriennummer [zertifikatNrHex]
37
+ * (hexadezimal, z. B. `6F0404F0`).
38
+ *
39
+ * **Der Returncode wird vor dem Status gelesen** (wie im Dart-Vorbild): `B33`
40
+ * heisst "nicht registriert" und schlaegt jedes Statusfeld, das daneben stehen
41
+ * mag. Andersherum meldete eine nie registrierte Karte am Ende "in Betrieb".
42
+ */
43
+ export declare function getSignatureStatus(rufen: KasseneckTransport, zertifikatNrHex: string): Promise<SignatureStatus>;
@@ -0,0 +1,43 @@
1
+ import { KasseneckValidationError } from './errors.js';
2
+ /**
3
+ * Vorgangsnamen, unter denen Fehler dieser beiden Abfragen erscheinen. Beide
4
+ * laufen ueber denselben Endpunkt `financeWebService`; ein Fehler, der nur den
5
+ * Endpunkt nennt, verschweigt dem Aufrufer, ob der Kassen- oder der
6
+ * Signaturstatus scheiterte. Der Transport bildet denselben Namen aus
7
+ * `<funktion>/<method>` — hier stehen die Konstanten fuer die Fehler, die schon
8
+ * vor dem Senden entstehen.
9
+ */
10
+ const VORGANG_KASSE = 'financeWebService/status_cashbox';
11
+ const VORGANG_SIGNATUR = 'financeWebService/status_signature';
12
+ /** Betriebsstatus der Kasse bei FinanzOnline. */
13
+ export async function getCashboxStatus(rufen) {
14
+ const daten = await rufen('financeWebService', {}, { method: 'status_cashbox' });
15
+ return statusAusMeldung(daten, VORGANG_KASSE);
16
+ }
17
+ /**
18
+ * Status der Signatureinheit mit der Zertifikatsseriennummer [zertifikatNrHex]
19
+ * (hexadezimal, z. B. `6F0404F0`).
20
+ *
21
+ * **Der Returncode wird vor dem Status gelesen** (wie im Dart-Vorbild): `B33`
22
+ * heisst "nicht registriert" und schlaegt jedes Statusfeld, das daneben stehen
23
+ * mag. Andersherum meldete eine nie registrierte Karte am Ende "in Betrieb".
24
+ */
25
+ export async function getSignatureStatus(rufen, zertifikatNrHex) {
26
+ if (typeof zertifikatNrHex !== 'string' || !zertifikatNrHex.trim()) {
27
+ throw new KasseneckValidationError(VORGANG_SIGNATUR, 'zertifikatNrHex fehlt', 'request');
28
+ }
29
+ const daten = await rufen('financeWebService', { zertifikatnr_hex: zertifikatNrHex }, { method: 'status_signature' });
30
+ if (daten?.rkdbMessage?.rc === 'B33') {
31
+ return 'NOT_REGISTERED';
32
+ }
33
+ return statusAusMeldung(daten, VORGANG_SIGNATUR);
34
+ }
35
+ function statusAusMeldung(daten, functionName) {
36
+ const status = daten?.rkdbMessage?.status;
37
+ if (typeof status !== 'string' || !status) {
38
+ // Der Inhalt der Antwort wandert NICHT in die Meldung — er kommt von einer
39
+ // fremden Stelle, und was dort steht, ist nicht unsere Zusage.
40
+ throw new KasseneckValidationError(functionName, 'Antwort enthaelt keinen Status (data.rkdbMessage.status)', 'response');
41
+ }
42
+ return status;
43
+ }