@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,51 @@
1
+ /**
2
+ * Unterpfad `@kreiseck/kasseneck-api/register` — die **Anmeldung der
3
+ * Browser-Kasse**: ein Geraet koppeln, seine Kassen-Benutzer auflisten, einen
4
+ * davon per PIN anmelden (mit oder ohne Benutzerauswahl), und die entstandene
5
+ * Sitzung erneuern bzw. beenden.
6
+ *
7
+ * Diese Aufrufe stehen vor allen anderen: ohne sie gibt es keine
8
+ * Identitaet, mit der ein Beleg entstehen koennte.
9
+ *
10
+ * **Sie zerfallen in zwei Haelften, und der Unterschied ist wesentlich:**
11
+ *
12
+ * | Aufruf | Anmeldung |
13
+ * |---|---|
14
+ * | [pairRegisterDevice] | **keine** — der Kopplungs-Code ist der Nachweis |
15
+ * | [listRegisterUsersForDevice] | **keine** — der Ausweis des Geraets ist der Nachweis |
16
+ * | [unpairRegisterDevice] | **keine** — der Ausweis des Geraets; sperrt es im Backend (Entkoppeln) |
17
+ * | [registerUserLogin] | **keine** — dieser Aufruf erzeugt sie |
18
+ * | [registerPinLogin] | **keine** — wie registerUserLogin, nur ohne Benutzerauswahl (Geraete-Modus `pin`) |
19
+ * | [renewRegisterSession] | Kassen-Benutzer (`registerUserAuth`) |
20
+ * | [endRegisterSession] | Kassen-Benutzer (`registerUserAuth`) |
21
+ *
22
+ * Die ersten drei nehmen deshalb **keinen Transport** entgegen, sondern nur
23
+ * die Verbindungsangaben, und bauen ihn selbst — die anmeldungsfreie Anmeldung
24
+ * dahinter wird bewusst nicht exportiert, sonst liesse sich damit jeder Aufruf
25
+ * des Pakets ohne Anmeldung bauen (ausfuehrlich in pairing.ts). Die letzten
26
+ * beiden nehmen den Transport wie jeder andere Endpunkt-Aufruf und stehen
27
+ * zusaetzlich in `createKasseneckApi`.
28
+ *
29
+ * Der uebliche Ablauf einer Browser-Kasse:
30
+ *
31
+ * ```ts
32
+ * import {
33
+ * pairRegisterDevice, listRegisterUsersForDevice, registerUserLogin,
34
+ * } from '@kreiseck/kasseneck-api/register';
35
+ *
36
+ * // Einmalig: Code aus dem Panel gegen den Geraeteausweis tauschen.
37
+ * const geraet = await pairRegisterDevice({ code: 'K7NPQR34', label: 'Schank' });
38
+ *
39
+ * // Bei jedem Schichtwechsel: auswaehlen und per PIN anmelden.
40
+ * const { users } = await listRegisterUsersForDevice(geraet);
41
+ * const sitzung = await registerUserLogin({
42
+ * ...geraet, userId: users[0]!.id, pin: '1234', cashregisterId: geraet.cashregisterId,
43
+ * });
44
+ * ```
45
+ *
46
+ * Mit `sitzung.customToken` meldet sich der Verbraucher bei Firebase an; das
47
+ * daraus entstehende ID-Token und `sitzung.sessionId` ergeben zusammen
48
+ * `registerUserAuth` — ab da laeuft alles Weitere ueber den ueblichen Weg.
49
+ */
50
+ export { pairRegisterDevice, listRegisterUsersForDevice, unpairRegisterDevice, registerUserLogin, registerPinLogin, } from './pairing.js';
51
+ export { renewRegisterSession, endRegisterSession } from './session.js';
@@ -0,0 +1,248 @@
1
+ import { type TransportOptions } from '../client/transport.js';
2
+ import { type ReceiptCompany } from '../models/receipt-company.js';
3
+ import { type KasseSettings } from '../kasse/settings.js';
4
+ /**
5
+ * Verbindungsangaben ohne Anmeldung — alles, was [TransportOptions] ausser der
6
+ * Anmeldung fuehrt. Alle Felder sind wahlfrei: ohne Angabe gelten Basis-URL und
7
+ * Zeitlimit der Produktion und das globale `fetch`.
8
+ */
9
+ export type RegisterDeviceConnection = Omit<TransportOptions, 'auth'>;
10
+ /** Ausweis eines gekoppelten Geraets — Nachweis der beiden Folgeaufrufe. */
11
+ export interface RegisterDeviceCredentials {
12
+ /** Kunde, unter dem das Geraet haengt (aus der Kopplung). */
13
+ ownerUid: string;
14
+ /** Dieses Geraet (aus der Kopplung). */
15
+ deviceId: string;
16
+ /** Geheimnis dieses Geraets; das Backend liefert es genau einmal aus. */
17
+ deviceSecret: string;
18
+ }
19
+ /** Was das Geraet ueber sich sagt -- fuer das Panel (welches Geraet ist das?). Alles optional. */
20
+ export interface RegisterClientInfo {
21
+ userAgent?: string;
22
+ platform?: string;
23
+ language?: string;
24
+ /** IANA-Zeitzone, z. B. Europe/Vienna. */
25
+ tz?: string;
26
+ screen?: {
27
+ w: number;
28
+ h: number;
29
+ };
30
+ }
31
+ /** Standort aus der Browser-Ortung (freiwillig); Grundlage der Standortsperre. */
32
+ export interface RegisterGeo {
33
+ lat: number;
34
+ lng: number;
35
+ /** Genauigkeit in Metern. */
36
+ acc?: number;
37
+ }
38
+ /** Angaben, die Kopplung und Login zusaetzlich mitschicken duerfen. */
39
+ export interface RegisterGeraeteAngaben {
40
+ client?: RegisterClientInfo;
41
+ geo?: RegisterGeo | null;
42
+ }
43
+ export interface PairRegisterDeviceOptions extends RegisterDeviceConnection, RegisterGeraeteAngaben {
44
+ /**
45
+ * Achtstelliger Kopplungs-Code aus dem Panel. Er ist 15 Minuten gueltig,
46
+ * genau **einmal** verwendbar und gilt fuer eine bestimmte Kasse.
47
+ *
48
+ * Gross-/Kleinschreibung und Leerzeichen an den Raendern sind gleichgueltig:
49
+ * das Backend beschneidet und schreibt gross. Dieses Paket prueft das Format
50
+ * **nicht** — es kennt das Alphabet nicht und wuerde eine spaetere Erweiterung
51
+ * ausschliessen.
52
+ */
53
+ code: string;
54
+ /** Bezeichnung dieses Geraets in der Geraeteliste; ohne Angabe "Kasse". */
55
+ label?: string;
56
+ }
57
+ /** Ergebnis der Kopplung — der vollstaendige Ausweis dieses Geraets. */
58
+ export interface PairedRegisterDevice extends RegisterDeviceCredentials {
59
+ /** Kasse, an die die Kopplung dieses Geraet gebunden hat. */
60
+ cashregisterId: string;
61
+ /** Firmenname des Betriebs (Backend: `betrieb`) — Anzeige, kann leer sein. */
62
+ companyName: string;
63
+ /** Bezeichnung der Kasse (Backend: `kasse`) — Anzeige, kann leer sein. */
64
+ cashregisterLabel: string;
65
+ }
66
+ /**
67
+ * Art eines Kassen-Benutzers: eine Person oder ein Geraet (Sammelkonto). Ein
68
+ * kuenftiger, hier noch unbekannter Wert kommt unveraendert durch, statt still
69
+ * zu "person" zu werden — beim Lesen ist dieses Paket tolerant.
70
+ */
71
+ export type RegisterUserKind = 'person' | 'device' | (string & {});
72
+ /** Ein Kassen-Benutzer, wie ihn der Anmeldebildschirm zeigt. */
73
+ export interface RegisterUserSummary {
74
+ id: string;
75
+ /** Anzeigename; kann leer sein. */
76
+ name: string;
77
+ kind: RegisterUserKind;
78
+ /**
79
+ * Die PIN dieses Benutzers wurde noch nicht unter der aktuellen Regel des
80
+ * Betriebs gesetzt: die Kasse zeigt ihm das Freifeld statt der Kaestchen.
81
+ * Das Backend sendet das Feld nur, wenn es zutrifft; gelesen ist es immer da.
82
+ */
83
+ altbestand: boolean;
84
+ }
85
+ /** PIN-Regel des Betriebs — daraus baut die Kasse Kaestchen und Tastatur. */
86
+ export interface RegisterPinPolicy {
87
+ /** Feste Stellenzahl (Backend: 3 bis 6). */
88
+ stellen: number;
89
+ /** `ziffern` (nur 0-9) oder `zeichen` (0-9 plus Kopplungs-Alphabet). */
90
+ zeichen: 'ziffern' | 'zeichen' | (string & {});
91
+ }
92
+ /** Anmeldemodus des Geraets; ein unbekannter kuenftiger Wert kommt durch. */
93
+ export type RegisterLoginMode = 'auswahl' | 'pin' | (string & {});
94
+ /** Antwort von [listRegisterUsersForDevice]: Benutzer, Regel, Modus. */
95
+ export interface RegisterDeviceUsers {
96
+ /** Im Modus `pin` bewusst leer — Namen haben am nur-PIN-Geraet nichts verloren. */
97
+ users: RegisterUserSummary[];
98
+ /** Kassen-Einstellungen (betriebsweit + Geraet), gemischt mit den Standardwerten. */
99
+ settings: KasseSettings;
100
+ /** Belegkopf-Daten des Betriebs (Name, Anschrift, UID, Fusszeilen) -- ohne Geheimnisse. */
101
+ betriebsdaten: ReceiptCompany | null;
102
+ /**
103
+ * `null`, wenn das Backend (noch) keine Regel nennt — dann zeigt die Kasse
104
+ * das Freifeld, statt Kaestchen mit einer erratenen Stellenzahl.
105
+ */
106
+ policy: RegisterPinPolicy | null;
107
+ loginMode: RegisterLoginMode;
108
+ /** Der Betrieb verlangt die Ortung beim Login (Standortsperre an). */
109
+ standortsperre: boolean;
110
+ }
111
+ /**
112
+ * Rechte eines Kassen-Benutzers (Backend: `perms`, Vorlagen `PERMS_KASSIER`
113
+ * und `PERMS_CHEF`). Der Inhaber kann einzelne Rechte abweichend setzen,
114
+ * deshalb sind weitere Schluessel zugelassen.
115
+ *
116
+ * **Ein fehlendes Recht gilt als nicht erteilt.** Die Oberflaeche soll im
117
+ * Zweifel weniger anbieten, nicht mehr; die tatsaechliche Grenze zieht ohnehin
118
+ * das Backend.
119
+ */
120
+ /** Reichweite eines Rechts: keine | nur eigene Belege | alle. */
121
+ export type RegisterScope = 'none' | 'own' | 'all';
122
+ export interface RegisterUserPerms {
123
+ /** Belege ausstellen. */
124
+ sell: boolean;
125
+ /** Belege stornieren (Schalter, gespiegelt aus cancelScope !== 'none'). */
126
+ cancel: boolean;
127
+ /** Artikelstamm bearbeiten. */
128
+ articles: boolean;
129
+ /** Beleglayout/Kassen-Einstellungen bearbeiten (Chef). */
130
+ layout: boolean;
131
+ /** Berichte ansehen. */
132
+ reports: boolean;
133
+ /** Eine belegte Kasse uebernehmen (nur Kassen-Chef). */
134
+ takeover: boolean;
135
+ /** Storno-Reichweite; fehlt bei Altbestand (dann zaehlt `cancel`: true = all). */
136
+ cancelScope?: RegisterScope;
137
+ /** Belege ansehen; fehlt bei Altbestand (= all). */
138
+ receiptsScope?: RegisterScope;
139
+ /** Kassenlade ohne Verkauf oeffnen. */
140
+ drawer?: boolean;
141
+ /** Rabatt geben. */
142
+ discount?: boolean;
143
+ /** Trinkgeld anderen zuweisen. */
144
+ tipAssign?: boolean;
145
+ [weiteresRecht: string]: boolean | RegisterScope | undefined;
146
+ }
147
+ /** Reichweite lesen, mit der Migration des Backends (register-auth.js). */
148
+ export declare function cancelScopeOf(perms: RegisterUserPerms | null | undefined): RegisterScope;
149
+ export declare function receiptsScopeOf(perms: RegisterUserPerms | null | undefined): RegisterScope;
150
+ /** Der angemeldete Kassen-Benutzer. */
151
+ export interface RegisterUser {
152
+ id: string;
153
+ name: string;
154
+ perms: RegisterUserPerms;
155
+ }
156
+ /** Ergebnis der PIN-Anmeldung. */
157
+ export interface RegisterUserSession {
158
+ /**
159
+ * Firebase-Custom-Token. Damit meldet der Verbraucher sich bei Firebase an
160
+ * und bekommt das ID-Token, das `registerUserAuth` braucht; dieses Paket
161
+ * kennt Firebase nicht.
162
+ */
163
+ customToken: string;
164
+ /** Laufende Sitzung — Kopfzeile `register-session` jedes weiteren Aufrufs. */
165
+ sessionId: string;
166
+ /**
167
+ * Ablauf der Sitzung in Millisekunden seit 1970 (das Backend rechnet hier mit
168
+ * `Date.now()`, nicht mit Wiener Wanduhrzeit). Die Sitzung lebt 90 Sekunden
169
+ * und will alle 30 Sekunden erneuert werden.
170
+ */
171
+ expiresAt: number;
172
+ user: RegisterUser;
173
+ }
174
+ export interface ListRegisterUsersForDeviceOptions extends RegisterDeviceConnection, RegisterDeviceCredentials {
175
+ }
176
+ export interface RegisterUserLoginOptions extends RegisterDeviceConnection, RegisterDeviceCredentials, RegisterGeraeteAngaben {
177
+ /** Kassen-Benutzer aus [listRegisterUsersForDevice]. */
178
+ userId: string;
179
+ /**
180
+ * PIN dieses Benutzers. Das Format prueft dieses Paket **nicht**: eine zu
181
+ * strenge Pruefung im Client sperrte Benutzer aus, deren PIN das Panel anders
182
+ * gesetzt hat.
183
+ */
184
+ pin: string;
185
+ /** Kasse, an der die Sitzung eroeffnet wird. */
186
+ cashregisterId: string;
187
+ /**
188
+ * Eine belegte Kasse uebernehmen. Nur mit dem Recht `takeover` (Kassen-Chef);
189
+ * die aelteste laufende Sitzung wird dabei verdraengt. Ohne das Recht bleibt
190
+ * es bei der Abweisung "Kasse wird gerade auf … verwendet".
191
+ */
192
+ takeover?: boolean;
193
+ }
194
+ export interface RegisterPinLoginOptions extends RegisterDeviceConnection, RegisterDeviceCredentials, RegisterGeraeteAngaben {
195
+ /**
196
+ * Die PIN allein — sie identifiziert UND authentifiziert (Geraete-Modus
197
+ * `pin`; das Backend haelt PINs je Betrieb eindeutig). Das Format prueft
198
+ * dieses Paket **nicht** — dieselbe Zurueckhaltung wie bei
199
+ * [RegisterUserLoginOptions.pin].
200
+ */
201
+ pin: string;
202
+ /** Kasse, an der die Sitzung eroeffnet wird. */
203
+ cashregisterId: string;
204
+ /** Wie [RegisterUserLoginOptions.takeover]. */
205
+ takeover?: boolean;
206
+ }
207
+ /**
208
+ * Geraet koppeln: der Kopplungs-Code wird gegen den dauerhaften Ausweis dieses
209
+ * Geraets getauscht. **Ohne Anmeldung** — der Code ist der Nachweis.
210
+ *
211
+ * Er wird dabei verbraucht, auch wenn der Aufrufer das Ergebnis verliert: eine
212
+ * unvollstaendige Antwort ist deshalb ein Fehler und kein halbes Geraet (siehe
213
+ * [PairedRegisterDevice]).
214
+ */
215
+ export declare function pairRegisterDevice(options: PairRegisterDeviceOptions): Promise<PairedRegisterDevice>;
216
+ /**
217
+ * Kassen-Benutzer dieses Betriebs auflisten — die Auswahl des
218
+ * Anmeldebildschirms. **Ohne Anmeldung**; der Ausweis des Geraets ist der
219
+ * Nachweis.
220
+ *
221
+ * Die Antwort traegt ausschliesslich Kennung, Name und Art: keine Rechte, keine
222
+ * Kassen, keine Hashes. Gesperrte Benutzer fehlen bereits in der Antwort.
223
+ */
224
+ /**
225
+ * „Geraet entkoppeln“ an der Kasse selbst: das Geraet weist sich mit seinem
226
+ * Geheimnis aus und sperrt sich im Backend — damit sieht das Panel den
227
+ * Widerruf und keine Sitzung laeuft nach. Idempotent: ein schon gesperrtes
228
+ * Geraet meldet Erfolg. Danach das Geraet lokal vergessen.
229
+ */
230
+ export declare function unpairRegisterDevice(options: ListRegisterUsersForDeviceOptions): Promise<void>;
231
+ export declare function listRegisterUsersForDevice(options: ListRegisterUsersForDeviceOptions): Promise<RegisterDeviceUsers>;
232
+ /**
233
+ * Kassen-Benutzer per PIN anmelden. **Ohne Anmeldung** — dieser Aufruf
234
+ * erzeugt sie: das Custom Token der Antwort wird zum ID-Token, die `sessionId`
235
+ * zur Kopfzeile `register-session`. Beides zusammen ergibt `registerUserAuth`.
236
+ *
237
+ * Das Backend prueft in dieser Reihenfolge: Geraet, Benutzer, Sperre, PIN,
238
+ * Kassenzuweisung, Kopplungsbindung, Lizenzplatz. Fehlversuche zaehlen und
239
+ * sperren gestaffelt (ab dem fuenften 30 Sekunden, ab dem neunten 15 Minuten).
240
+ */
241
+ export declare function registerUserLogin(options: RegisterUserLoginOptions): Promise<RegisterUserSession>;
242
+ /**
243
+ * Kassen-Benutzer allein mit der PIN anmelden (Geraete-Modus `pin`). **Ohne
244
+ * Anmeldung** — wie [registerUserLogin], nur ohne Benutzerauswahl: das Backend
245
+ * ermittelt den Benutzer ueber die betriebsweit eindeutige PIN. Fehlversuche
246
+ * zaehlen und sperren dort am **Geraet**, nicht an einem Benutzer.
247
+ */
248
+ export declare function registerPinLogin(options: RegisterPinLoginOptions): Promise<RegisterUserSession>;
@@ -0,0 +1,270 @@
1
+ import { KasseneckValidationError } from '../client/errors.js';
2
+ import { createTransport } from '../client/transport.js';
3
+ import { fromReceiptCompanyPayload } from '../models/receipt-company.js';
4
+ import { KASSE_BETRIEB_STANDARD, KASSE_GERAET_STANDARD, mergeKasseSettings, } from '../kasse/settings.js';
5
+ /**
6
+ * Die drei Aufrufe, die **ohne jede Identitaet** laufen: Kopplung eines
7
+ * Geraets, Benutzerliste dieses Geraets, PIN-Anmeldung. Sie sind der Weg, auf
8
+ * dem eine Identitaet ueberhaupt erst entsteht — vor ihnen gibt es weder
9
+ * ID-Token noch Sitzung noch `api_key`.
10
+ *
11
+ * **Warum sie keine Anmeldung und keinen Transport entgegennehmen.** Alle
12
+ * uebrigen Endpunkt-Aufrufe dieses Pakets bekommen einen fertigen
13
+ * [KasseneckTransport] als ersten Parameter. Hier ginge das nur mit einer
14
+ * anmeldungsfreien Anmeldung — und die muesste dann exportiert sein. Genau das
15
+ * waere ein Schlupfloch: mit ihr liesse sich `createTransport` bzw.
16
+ * `createKasseneckApi` bauen und damit **jeder** Aufruf des Pakets ohne
17
+ * Anmeldung absetzen, auch `createReceipt`. Das Backend wiese das ab, aber ein
18
+ * Paket, das den Weg anbietet, sagt damit, dass es ihn gibt.
19
+ *
20
+ * Deshalb nehmen diese drei nur die **Verbindungsangaben** (Basis-URL,
21
+ * Zeitlimit, `fetch`) entgegen und bauen ihren Transport selbst — mit einer
22
+ * Anmeldung, die diese Datei nicht verlaesst. Damit gibt es im ganzen Paket
23
+ * keinen Weg, einen anmeldungsfreien Transport in die Hand zu bekommen.
24
+ *
25
+ * **Geheimnisse in der Nutzlast.** Diese drei Aufrufe fuehren Kopplungs-Code,
26
+ * Geraetegeheimnis und PIN — nicht in Kopfzeilen, sondern im Rumpf. Der
27
+ * Transport schuetzt seine Fehler von sich aus nur gegen die Werte, die er als
28
+ * Kopfzeilen gesendet hat (siehe client/errors.ts, `causeDigest`); hier ist
29
+ * diese Liste leer. Die Aufrufe nennen ihm ihre Geheimnisse deshalb
30
+ * ausdruecklich, sonst kaeme ein bezeichner-foermiges Geraetegeheimnis ueber
31
+ * die verdichtete Ursache eines Netzfehlers doch noch ins Protokoll.
32
+ */
33
+ /**
34
+ * Anmeldung, die keine ist: weder Kopfzeilen noch Zusatzparameter.
35
+ *
36
+ * **Nicht exportiert und niemals exportieren** — der Grund steht im
37
+ * Modulkommentar. Pro Aufruf ein frisches Objekt, wie die echten Anmeldungen
38
+ * es auch halten.
39
+ */
40
+ const ohneAnmeldung = () => ({ headers: {}, params: {} });
41
+ /** Reichweite lesen, mit der Migration des Backends (register-auth.js). */
42
+ export function cancelScopeOf(perms) {
43
+ if (!perms)
44
+ return 'none';
45
+ if (perms.cancelScope !== undefined)
46
+ return ['none', 'own', 'all'].includes(perms.cancelScope) ? perms.cancelScope : 'none';
47
+ return perms.cancel === true ? 'all' : 'none';
48
+ }
49
+ export function receiptsScopeOf(perms) {
50
+ if (!perms)
51
+ return 'none';
52
+ if (perms.receiptsScope === undefined)
53
+ return 'all';
54
+ return ['none', 'own', 'all'].includes(perms.receiptsScope) ? perms.receiptsScope : 'none';
55
+ }
56
+ /**
57
+ * Geraet koppeln: der Kopplungs-Code wird gegen den dauerhaften Ausweis dieses
58
+ * Geraets getauscht. **Ohne Anmeldung** — der Code ist der Nachweis.
59
+ *
60
+ * Er wird dabei verbraucht, auch wenn der Aufrufer das Ergebnis verliert: eine
61
+ * unvollstaendige Antwort ist deshalb ein Fehler und kein halbes Geraet (siehe
62
+ * [PairedRegisterDevice]).
63
+ */
64
+ export async function pairRegisterDevice(options) {
65
+ const { code, label, client, geo, ...verbindung } = options;
66
+ pflicht('pairRegisterDevice', 'code', code);
67
+ // Der Code ist das Geheimnis dieses Aufrufs — siehe Modulkommentar.
68
+ const daten = await transportFuer(verbindung)('pairRegisterDevice', { code, label, client, geo: geo ?? undefined }, undefined, [code]);
69
+ return {
70
+ deviceId: pflichtfeld('pairRegisterDevice', daten, 'deviceId'),
71
+ deviceSecret: pflichtfeld('pairRegisterDevice', daten, 'deviceSecret'),
72
+ ownerUid: pflichtfeld('pairRegisterDevice', daten, 'ownerUid'),
73
+ cashregisterId: pflichtfeld('pairRegisterDevice', daten, 'cashregisterId'),
74
+ companyName: text(daten?.['betrieb']),
75
+ cashregisterLabel: text(daten?.['kasse']),
76
+ };
77
+ }
78
+ /**
79
+ * Kassen-Benutzer dieses Betriebs auflisten — die Auswahl des
80
+ * Anmeldebildschirms. **Ohne Anmeldung**; der Ausweis des Geraets ist der
81
+ * Nachweis.
82
+ *
83
+ * Die Antwort traegt ausschliesslich Kennung, Name und Art: keine Rechte, keine
84
+ * Kassen, keine Hashes. Gesperrte Benutzer fehlen bereits in der Antwort.
85
+ */
86
+ /**
87
+ * „Geraet entkoppeln“ an der Kasse selbst: das Geraet weist sich mit seinem
88
+ * Geheimnis aus und sperrt sich im Backend — damit sieht das Panel den
89
+ * Widerruf und keine Sitzung laeuft nach. Idempotent: ein schon gesperrtes
90
+ * Geraet meldet Erfolg. Danach das Geraet lokal vergessen.
91
+ */
92
+ export async function unpairRegisterDevice(options) {
93
+ const { ownerUid, deviceId, deviceSecret, ...verbindung } = options;
94
+ const name = 'unpairRegisterDevice';
95
+ pflicht(name, 'ownerUid', ownerUid);
96
+ pflicht(name, 'deviceId', deviceId);
97
+ pflicht(name, 'deviceSecret', deviceSecret);
98
+ await transportFuer(verbindung)(name, { ownerUid, deviceId, deviceSecret }, undefined, [deviceSecret]);
99
+ }
100
+ export async function listRegisterUsersForDevice(options) {
101
+ const { ownerUid, deviceId, deviceSecret, ...verbindung } = options;
102
+ const name = 'listRegisterUsersForDevice';
103
+ pflicht(name, 'ownerUid', ownerUid);
104
+ pflicht(name, 'deviceId', deviceId);
105
+ pflicht(name, 'deviceSecret', deviceSecret);
106
+ const daten = await transportFuer(verbindung)(name, { ownerUid, deviceId, deviceSecret }, undefined, [deviceSecret]);
107
+ const liste = daten?.users;
108
+ if (!Array.isArray(liste)) {
109
+ throw antwortfehler(name, 'Antwort enthaelt keine Benutzerliste (data.users fehlt)');
110
+ }
111
+ const users = liste.map((eintrag) => {
112
+ const roh = (typeof eintrag === 'object' && eintrag !== null ? eintrag : {});
113
+ return {
114
+ // Ein Eintrag ohne Kennung ist nicht anmeldbar — ihn anzuzeigen hiesse,
115
+ // dem Kassier eine Schaltflaeche zu geben, die nichts tun kann.
116
+ id: pflichtfeld(name, roh, 'id'),
117
+ name: text(roh['name']),
118
+ kind: typeof roh['kind'] === 'string' && roh['kind'] ? roh['kind'] : 'person',
119
+ altbestand: roh['altbestand'] === true,
120
+ };
121
+ });
122
+ const settingsRoh = (daten?.settings ?? {});
123
+ const settings = {
124
+ betrieb: mergeKasseSettings(KASSE_BETRIEB_STANDARD, (settingsRoh.betrieb ?? null)),
125
+ geraet: mergeKasseSettings(KASSE_GERAET_STANDARD, (settingsRoh.geraet ?? null)),
126
+ };
127
+ const bd = daten?.betriebsdaten;
128
+ const betriebsdaten = bd && typeof bd === 'object' ? fromReceiptCompanyPayload(bd) : null;
129
+ return { users, policy: regel(daten?.policy), loginMode: daten?.loginMode === 'pin' ? 'pin' : 'auswahl', settings, betriebsdaten, standortsperre: daten?.standortsperre === true };
130
+ }
131
+ /** Die Regel aus der Antwort — oder `null`, wenn keine brauchbare kommt. */
132
+ function regel(wert) {
133
+ if (typeof wert !== 'object' || wert === null || Array.isArray(wert))
134
+ return null;
135
+ const roh = wert;
136
+ const stellen = roh['stellen'];
137
+ const zeichen = roh['zeichen'];
138
+ if (typeof stellen !== 'number' || !Number.isInteger(stellen) || stellen < 1)
139
+ return null;
140
+ if (typeof zeichen !== 'string' || zeichen === '')
141
+ return null;
142
+ return { stellen, zeichen: zeichen };
143
+ }
144
+ /**
145
+ * Kassen-Benutzer per PIN anmelden. **Ohne Anmeldung** — dieser Aufruf
146
+ * erzeugt sie: das Custom Token der Antwort wird zum ID-Token, die `sessionId`
147
+ * zur Kopfzeile `register-session`. Beides zusammen ergibt `registerUserAuth`.
148
+ *
149
+ * Das Backend prueft in dieser Reihenfolge: Geraet, Benutzer, Sperre, PIN,
150
+ * Kassenzuweisung, Kopplungsbindung, Lizenzplatz. Fehlversuche zaehlen und
151
+ * sperren gestaffelt (ab dem fuenften 30 Sekunden, ab dem neunten 15 Minuten).
152
+ */
153
+ export async function registerUserLogin(options) {
154
+ const { ownerUid, deviceId, deviceSecret, userId, pin, cashregisterId, takeover, client, geo, ...verbindung } = options;
155
+ const name = 'registerUserLogin';
156
+ pflicht(name, 'ownerUid', ownerUid);
157
+ pflicht(name, 'deviceId', deviceId);
158
+ pflicht(name, 'deviceSecret', deviceSecret);
159
+ pflicht(name, 'userId', userId);
160
+ pflicht(name, 'pin', pin);
161
+ pflicht(name, 'cashregisterId', cashregisterId);
162
+ const daten = await transportFuer(verbindung)(name, {
163
+ ownerUid,
164
+ deviceId,
165
+ deviceSecret,
166
+ userId,
167
+ pin,
168
+ cashregisterId,
169
+ // Nur die ausdrueckliche Uebernahme geht mit: das Backend prueft auf
170
+ // `=== true`, und ein mitgesendetes `false` waere nur Rauschen.
171
+ takeover: takeover === true ? true : undefined,
172
+ client, geo: geo ?? undefined,
173
+ }, undefined, [pin, deviceSecret]);
174
+ return sitzungAusAntwort(name, daten);
175
+ }
176
+ /**
177
+ * Kassen-Benutzer allein mit der PIN anmelden (Geraete-Modus `pin`). **Ohne
178
+ * Anmeldung** — wie [registerUserLogin], nur ohne Benutzerauswahl: das Backend
179
+ * ermittelt den Benutzer ueber die betriebsweit eindeutige PIN. Fehlversuche
180
+ * zaehlen und sperren dort am **Geraet**, nicht an einem Benutzer.
181
+ */
182
+ export async function registerPinLogin(options) {
183
+ const { ownerUid, deviceId, deviceSecret, pin, cashregisterId, takeover, client, geo, ...verbindung } = options;
184
+ const name = 'registerPinLogin';
185
+ pflicht(name, 'ownerUid', ownerUid);
186
+ pflicht(name, 'deviceId', deviceId);
187
+ pflicht(name, 'deviceSecret', deviceSecret);
188
+ pflicht(name, 'pin', pin);
189
+ pflicht(name, 'cashregisterId', cashregisterId);
190
+ const daten = await transportFuer(verbindung)(name, {
191
+ ownerUid,
192
+ deviceId,
193
+ deviceSecret,
194
+ pin,
195
+ cashregisterId,
196
+ // Nur die ausdrueckliche Uebernahme geht mit — wie bei registerUserLogin.
197
+ takeover: takeover === true ? true : undefined,
198
+ client, geo: geo ?? undefined,
199
+ }, undefined, [pin, deviceSecret]);
200
+ return sitzungAusAntwort(name, daten);
201
+ }
202
+ /** Die Sitzungsantwort beider Anmeldewege — ein Vertrag, eine Lesart. */
203
+ function sitzungAusAntwort(name, daten) {
204
+ const roherBenutzer = daten?.['user'];
205
+ if (typeof roherBenutzer !== 'object' || roherBenutzer === null || Array.isArray(roherBenutzer)) {
206
+ throw antwortfehler(name, 'Antwort enthaelt keinen Benutzer (data.user fehlt)');
207
+ }
208
+ const benutzer = roherBenutzer;
209
+ const expiresAt = daten?.['expiresAt'];
210
+ if (typeof expiresAt !== 'number' || !Number.isFinite(expiresAt)) {
211
+ throw antwortfehler(name, 'Antwort enthaelt keinen Ablaufzeitpunkt (data.expiresAt fehlt)');
212
+ }
213
+ return {
214
+ customToken: pflichtfeld(name, daten, 'customToken'),
215
+ sessionId: pflichtfeld(name, daten, 'sessionId'),
216
+ expiresAt,
217
+ user: {
218
+ id: pflichtfeld(name, benutzer, 'id'),
219
+ name: text(benutzer['name']),
220
+ perms: rechte(benutzer['perms']),
221
+ },
222
+ };
223
+ }
224
+ /** Transport ohne Anmeldung; `auth` steht zuletzt und ist damit nicht zu ueberschreiben. */
225
+ function transportFuer(verbindung) {
226
+ return createTransport({ ...verbindung, auth: ohneAnmeldung });
227
+ }
228
+ /**
229
+ * Pflichtangabe des Aufrufers. Die Meldung nennt das **Feld**, nie seinen Wert
230
+ * — das Feld heisst `pin`, `deviceSecret` oder `code`.
231
+ */
232
+ function pflicht(functionName, feld, wert) {
233
+ if (typeof wert !== 'string' || wert.trim() === '') {
234
+ throw new KasseneckValidationError(functionName, `${feld} fehlt`, 'request');
235
+ }
236
+ }
237
+ /**
238
+ * Pflichtfeld der Antwort. Auch hier wandert **nichts aus der Antwort** in die
239
+ * Meldung; genannt wird nur, welches Feld fehlt.
240
+ */
241
+ function pflichtfeld(functionName, daten, feld) {
242
+ const wert = daten?.[feld];
243
+ if (typeof wert !== 'string' || wert === '') {
244
+ throw antwortfehler(functionName, `Antwort enthaelt kein Feld "${feld}"`);
245
+ }
246
+ return wert;
247
+ }
248
+ /** Rechte lesen: nur Wahrheitswerte, alles Fehlende gilt als nicht erteilt. */
249
+ function rechte(wert) {
250
+ const roh = (typeof wert === 'object' && wert !== null && !Array.isArray(wert) ? wert : {});
251
+ const gelesen = {};
252
+ for (const [name, inhalt] of Object.entries(roh)) {
253
+ gelesen[name] = inhalt === true;
254
+ }
255
+ return {
256
+ sell: false,
257
+ cancel: false,
258
+ articles: false,
259
+ layout: false,
260
+ reports: false,
261
+ takeover: false,
262
+ ...gelesen,
263
+ };
264
+ }
265
+ /** Leere Zeichenkette statt `undefined` — Anzeigefelder duerfen leer sein. */
266
+ const text = (wert) => (typeof wert === 'string' ? wert : '');
267
+ /** Die Antwort meldete Erfolg, trug aber nicht, was der Aufruf zusagt. */
268
+ function antwortfehler(functionName, grund) {
269
+ return new KasseneckValidationError(functionName, grund, 'response');
270
+ }
@@ -0,0 +1,37 @@
1
+ import type { KasseneckTransport } from '../client/transport.js';
2
+ /**
3
+ * Die beiden Aufrufe der **laufenden** Kassen-Sitzung. Anders als die drei in
4
+ * pairing.ts haben sie eine Identitaet: sie laufen ueber `registerUserAuth`
5
+ * (ID-Token als Bearer, Sitzung als Kopfzeile `register-session`) und nehmen
6
+ * darum einen fertigen [KasseneckTransport] entgegen wie jeder andere
7
+ * Endpunkt-Aufruf dieses Pakets.
8
+ *
9
+ * Beide fuehren **keinen einzigen Parameter**: welche Sitzung gemeint ist,
10
+ * steht im Token und in der Kopfzeile. Der Parameter `cashregisterId`, den man
11
+ * im Rumpf sieht, kommt aus der Anmeldung.
12
+ *
13
+ * Das Backend setzt fuer beide `allowRegisterUser`; mit `apiKeyAuth` sind sie
14
+ * nicht erreichbar (dieses Paket bildet das nicht nach — wer darf, entscheidet
15
+ * das Backend).
16
+ */
17
+ /**
18
+ * Sitzung verlaengern und den neuen Ablaufzeitpunkt liefern (Millisekunden
19
+ * seit 1970).
20
+ *
21
+ * Die Sitzung lebt 90 Sekunden; die Browser-Kasse erneuert alle 30. Ist sie
22
+ * bereits beendet oder uebernommen, antwortet das Backend fachlich ("Sitzung
23
+ * beendet — bitte neu anmelden.") — dann hilft nur eine neue Anmeldung ueber
24
+ * `registerUserLogin`.
25
+ */
26
+ export declare function renewRegisterSession(rufen: KasseneckTransport): Promise<number>;
27
+ /**
28
+ * Sitzung beenden und den Lizenzplatz sofort freigeben — der regulaere Weg des
29
+ * Abmeldens.
30
+ *
31
+ * Das Backend antwortet mit `{ok:true}`; dieser Aufruf prueft das Feld
32
+ * **nicht**: dass der Vorgang gelang, sagt bereits die Erfolgshuelle, die der
33
+ * Transport auswertet. Eine zweite Pruefung derselben Aussage braeche nur an
34
+ * einer harmlosen Vertragsaenderung — ausgerechnet beim Abmelden, dem Aufruf,
35
+ * der auch dann durchgehen soll, wenn sonst nichts mehr geht.
36
+ */
37
+ export declare function endRegisterSession(rufen: KasseneckTransport): Promise<void>;
@@ -0,0 +1,48 @@
1
+ import { KasseneckValidationError } from '../client/errors.js';
2
+ /**
3
+ * Die beiden Aufrufe der **laufenden** Kassen-Sitzung. Anders als die drei in
4
+ * pairing.ts haben sie eine Identitaet: sie laufen ueber `registerUserAuth`
5
+ * (ID-Token als Bearer, Sitzung als Kopfzeile `register-session`) und nehmen
6
+ * darum einen fertigen [KasseneckTransport] entgegen wie jeder andere
7
+ * Endpunkt-Aufruf dieses Pakets.
8
+ *
9
+ * Beide fuehren **keinen einzigen Parameter**: welche Sitzung gemeint ist,
10
+ * steht im Token und in der Kopfzeile. Der Parameter `cashregisterId`, den man
11
+ * im Rumpf sieht, kommt aus der Anmeldung.
12
+ *
13
+ * Das Backend setzt fuer beide `allowRegisterUser`; mit `apiKeyAuth` sind sie
14
+ * nicht erreichbar (dieses Paket bildet das nicht nach — wer darf, entscheidet
15
+ * das Backend).
16
+ */
17
+ /**
18
+ * Sitzung verlaengern und den neuen Ablaufzeitpunkt liefern (Millisekunden
19
+ * seit 1970).
20
+ *
21
+ * Die Sitzung lebt 90 Sekunden; die Browser-Kasse erneuert alle 30. Ist sie
22
+ * bereits beendet oder uebernommen, antwortet das Backend fachlich ("Sitzung
23
+ * beendet — bitte neu anmelden.") — dann hilft nur eine neue Anmeldung ueber
24
+ * `registerUserLogin`.
25
+ */
26
+ export async function renewRegisterSession(rufen) {
27
+ const daten = await rufen('renewRegisterSession');
28
+ const expiresAt = daten?.expiresAt;
29
+ if (typeof expiresAt !== 'number' || !Number.isFinite(expiresAt)) {
30
+ // Ohne brauchbaren Ablaufzeitpunkt weiss die Kasse nicht, wann sie das
31
+ // naechste Mal erneuern muss — das ist ein Antwortfehler und kein Erfolg.
32
+ throw new KasseneckValidationError('renewRegisterSession', 'Antwort enthaelt keinen Ablaufzeitpunkt (data.expiresAt fehlt)', 'response');
33
+ }
34
+ return expiresAt;
35
+ }
36
+ /**
37
+ * Sitzung beenden und den Lizenzplatz sofort freigeben — der regulaere Weg des
38
+ * Abmeldens.
39
+ *
40
+ * Das Backend antwortet mit `{ok:true}`; dieser Aufruf prueft das Feld
41
+ * **nicht**: dass der Vorgang gelang, sagt bereits die Erfolgshuelle, die der
42
+ * Transport auswertet. Eine zweite Pruefung derselben Aussage braeche nur an
43
+ * einer harmlosen Vertragsaenderung — ausgerechnet beim Abmelden, dem Aufruf,
44
+ * der auch dann durchgehen soll, wenn sonst nichts mehr geht.
45
+ */
46
+ export async function endRegisterSession(rufen) {
47
+ await rufen('endRegisterSession');
48
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Server-Zeitstempel parsen: ohne Offset = Wiener Wanduhrzeit, mit
3
+ * Offset/`Z` = bereits ein echter Zeitpunkt. Ergebnis ist immer ein echter
4
+ * Zeitpunkt (JS-`Date`, intern UTC-Millisekunden seit Epoch).
5
+ */
6
+ export declare function parseServerTimeStamp(raw: string): Date;
7
+ /** Wiener Wanduhrzeit: die Ziffern, die eine Uhr in Wien anzeigt. `month` ist 1-12. */
8
+ export interface ViennaWallClock {
9
+ year: number;
10
+ month: number;
11
+ day: number;
12
+ hour: number;
13
+ minute: number;
14
+ second: number;
15
+ millisecond: number;
16
+ }
17
+ /**
18
+ * Echter Zeitpunkt -> Wiener Wanduhrzeit (Gegenstueck zu
19
+ * [parseServerTimeStamp]). Der Versatz kommt aus derselben Sommerzeitregel wie
20
+ * die Hinrichtung; hier ist er direkt anwendbar, weil der Zeitpunkt schon
21
+ * feststeht.
22
+ */
23
+ export declare function toViennaWallClock(zeitpunkt: Date): ViennaWallClock;