@kreiseck/kasseneck-api 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/cjs/receipt/layout.d.ts +11 -5
  3. package/dist/cjs/receipt/layout.js +248 -26
  4. package/dist/esm/receipt/layout.d.ts +11 -5
  5. package/dist/esm/receipt/layout.js +247 -26
  6. package/fixtures/belege/karte-eigener.json +44 -0
  7. package/fixtures/belege/karte-gptom-ios.json +59 -0
  8. package/fixtures/belege/karte-gptom.json +59 -0
  9. package/fixtures/belege/karte-hobex-cloud.json +54 -0
  10. package/fixtures/belege/karte-hobex-hps.json +54 -0
  11. package/fixtures/belege/karte-mypos.json +55 -0
  12. package/fixtures/belege/karte-stripe-eps.json +52 -0
  13. package/fixtures/belege/karte-stripe.json +57 -0
  14. package/fixtures/belege/karte-sumup.json +53 -0
  15. package/fixtures/erwartet/karte-eigener.grid32.txt +22 -0
  16. package/fixtures/erwartet/karte-eigener.grid48.txt +22 -0
  17. package/fixtures/erwartet/karte-eigener.lines.json +216 -0
  18. package/fixtures/erwartet/karte-gptom-ios.grid32.txt +34 -0
  19. package/fixtures/erwartet/karte-gptom-ios.grid48.txt +34 -0
  20. package/fixtures/erwartet/karte-gptom-ios.lines.json +286 -0
  21. package/fixtures/erwartet/karte-gptom.grid32.txt +34 -0
  22. package/fixtures/erwartet/karte-gptom.grid48.txt +34 -0
  23. package/fixtures/erwartet/karte-gptom.lines.json +286 -0
  24. package/fixtures/erwartet/karte-hobex-cloud.grid32.txt +29 -0
  25. package/fixtures/erwartet/karte-hobex-cloud.grid48.txt +29 -0
  26. package/fixtures/erwartet/karte-hobex-cloud.lines.json +256 -0
  27. package/fixtures/erwartet/karte-hobex-hps.grid32.txt +33 -0
  28. package/fixtures/erwartet/karte-hobex-hps.grid48.txt +33 -0
  29. package/fixtures/erwartet/karte-hobex-hps.lines.json +272 -0
  30. package/fixtures/erwartet/karte-mypos.grid32.txt +38 -0
  31. package/fixtures/erwartet/karte-mypos.grid48.txt +36 -0
  32. package/fixtures/erwartet/karte-mypos.lines.json +353 -0
  33. package/fixtures/erwartet/karte-stripe-eps.grid32.txt +28 -0
  34. package/fixtures/erwartet/karte-stripe-eps.grid48.txt +28 -0
  35. package/fixtures/erwartet/karte-stripe-eps.lines.json +250 -0
  36. package/fixtures/erwartet/karte-stripe.grid32.txt +31 -0
  37. package/fixtures/erwartet/karte-stripe.grid48.txt +31 -0
  38. package/fixtures/erwartet/karte-stripe.lines.json +268 -0
  39. package/fixtures/erwartet/karte-sumup.grid32.txt +32 -0
  40. package/fixtures/erwartet/karte-sumup.grid48.txt +30 -0
  41. package/fixtures/erwartet/karte-sumup.lines.json +316 -0
  42. package/fixtures/hobex-hps-codes.json +1 -1
  43. package/fixtures/kasse-texte.json +1 -1
  44. package/fixtures/manifest.json +54 -0
  45. package/fixtures/oberflaeche.json +1 -1
  46. package/package.json +1 -1
@@ -60,6 +60,36 @@ function originalDatum(timeStamp) {
60
60
  * `typeof null === 'object'` ist, ergab das beim Lesen von `.label` einen
61
61
  * nackten TypeError.
62
62
  */
63
+ /**
64
+ * Die anbieterspezifischen Kartenzahlungsbloecke.
65
+ *
66
+ * WARUM DIESE BLOECKE HIER STEHEN
67
+ *
68
+ * Bis 0.8.0 trug dieses Modell nur den Hobex-Block, mit der Begruendung, die
69
+ * uebrigen Anbieter druckten "in ihren eigenen Apps". Das Argument gilt fuer
70
+ * die Frage, wer das TERMINAL bedient -- nicht dafuer, was auf dem
71
+ * BELEGDOKUMENT steht. Aus der einen Regel wurde die andere, und damit
72
+ * verschwanden vier Bloecke: Wer denselben Beleg als PDF oeffnete, sah "nur
73
+ * Kartenzahlung", waehrend der Bon daneben Marke, letzte Ziffern, Betrag und
74
+ * Referenz auswies. Vorher (backend `generateReceiptPdf`) hatte das PDF alle
75
+ * sieben Anbieter.
76
+ *
77
+ * Gebaut werden die Zeilen deshalb hier, an genau EINER Stelle. Wer sie
78
+ * anderswo noch einmal baut, oeffnet die Drift wieder.
79
+ *
80
+ * Vorbild ist `print_paper.dart` im Dart-Paket (`_gpTom`, `_hobexHps`,
81
+ * `_sumup`, `_mypos`, `_stripe`); die Fixtures unter `fixtures/belege/karte-*`
82
+ * halten je Anbieter eine Zeile-fuer-Zeile-Probe fest.
83
+ */
84
+ /** Ein Feld aus `cardPaymentData` als Text; fehlend/null wird leer. */
85
+ function kartenFeld(daten, schluessel) {
86
+ const v = daten[schluessel];
87
+ return v == null ? '' : String(v);
88
+ }
89
+ /** Nicht-leere Teile mit Mittelpunkt verbinden. */
90
+ function verbunden(teile) {
91
+ return teile.filter(Boolean).join(' · ');
92
+ }
63
93
  /**
64
94
  * Kartenzahlungsblock fuer Hobex (HPS am Geraet wie Cloud-API): die Felder
65
95
  * kommen aus `cardPaymentData` in der Form von [hobexReceiptToCardPaymentData]
@@ -67,43 +97,234 @@ function originalDatum(timeStamp) {
67
97
  * Antwortcode. Bei CVM "1" verlangt die Karte eine Unterschrift; dafuer
68
98
  * bekommt der Bon eine Linie. Der PAN haengt beim HPS das Ablaufdatum mit
69
99
  * Unterstrich an ("…4720_2810") — gedruckt wird nur die maskierte Nummer.
70
- *
71
- * Andere Anbieter (GP Tom, SumUp, myPOS, Stripe) drucken in ihren eigenen
72
- * Apps; ihre Bloecke bleiben bewusst draussen (siehe Kopfkommentar).
73
100
  */
74
- function hobexKartenblock(receipt) {
75
- const provider = receipt.creditCardProvider;
76
- const daten = receipt.cardPaymentData;
77
- if ((provider !== 'hobexHps' && provider !== 'hobexCloudApi') || daten == null) {
78
- return [];
79
- }
80
- const feld = (k) => {
81
- const v = daten[k];
82
- return v == null ? '' : String(v);
83
- };
84
- const paar = (teile) => teile.filter(Boolean).join(' · ');
85
- const pan = feld('cardNumber').split('_')[0] ?? '';
86
- const rc = feld('responseCode');
101
+ function hobexBlock(daten) {
102
+ const feld = (k) => kartenFeld(daten, k);
87
103
  const zeilen = [textZeile('Hobex Beleg', 'center', true)];
88
104
  const inhalt = [
89
105
  feld('date'),
90
- paar([feld('tid') && `TID ${feld('tid')}`, feld('no') && `Nr. ${feld('no')}`]),
91
- paar([feld('type'), feld('cardBrand')]),
92
- pan,
93
- rc && `RC ${rc}`,
106
+ verbunden([feld('tid') && `TID ${feld('tid')}`, feld('no') && `Nr. ${feld('no')}`]),
107
+ verbunden([feld('type'), feld('cardBrand')]),
108
+ feld('cardNumber').split('_')[0] ?? '',
109
+ feld('responseCode') && `RC ${feld('responseCode')}`,
110
+ ];
111
+ for (const zeile of inhalt) {
112
+ if (zeile)
113
+ zeilen.push(textZeile(zeile, 'center'));
114
+ }
115
+ if (feld('cvm') === '1')
116
+ zeilen.push(...unterschriftsfeld());
117
+ return zeilen;
118
+ }
119
+ /** Zwei Leerzeilen, Linie, Wort -- das Unterschriftsfeld auf dem Bon. */
120
+ function unterschriftsfeld() {
121
+ return [
122
+ { kind: 'space', lines: 2 },
123
+ textZeile('------------------', 'center'),
124
+ textZeile('Unterschrift', 'center'),
125
+ ];
126
+ }
127
+ /**
128
+ * GP-Tom-`transactionType`: das Plugin-`toMap` schreibt den Schluessel mit
129
+ * Tippfehler (`transacitonType`), aeltere Daten tragen ihn gar nicht. Beide
130
+ * Schreibweisen werden gelesen -- ein Beleg von damals soll nicht anders
131
+ * aussehen als einer von heute.
132
+ */
133
+ function gpTomVorgangsart(daten) {
134
+ switch (daten.transactionType ?? daten.transacitonType) {
135
+ case 1: return 'Sale';
136
+ case 2: return 'Void';
137
+ case 3: return 'Refund';
138
+ case 4: return 'Close Batch';
139
+ default: return '';
140
+ }
141
+ }
142
+ /** GP-Tom-Betrag: ganze Zahl = Cent, sonst schon ein Eurobetrag. */
143
+ function gpTomBetrag(wert) {
144
+ if (typeof wert !== 'number')
145
+ return '-';
146
+ return Number.isInteger(wert) ? formatCents(wert) : wert.toFixed(2).replace('.', ',');
147
+ }
148
+ function gpTomBlock(daten) {
149
+ const feld = (k) => kartenFeld(daten, k);
150
+ const art = gpTomVorgangsart(daten);
151
+ const zeilen = [textZeile('GP Tom Beleg', 'center', true)];
152
+ const inhalt = [
153
+ `Batch: ${feld('batchNumber')}`,
154
+ `Receipt: ${feld('externalTransactionID')}`,
155
+ `TID: ${feld('terminalID')}`,
156
+ feld('emvAid'),
157
+ (daten.emvAppLable != null || daten.cardDataEntry != null)
158
+ ? `${feld('emvAppLable')} ${feld('cardDataEntry')}`.trim() : '',
159
+ feld('cardNumber'),
160
+ `${art ? `${art} ` : ''}Amount ${feld('currencyCode')} ${gpTomBetrag(daten.amount)}`,
161
+ daten.pinOk === true ? 'PIN OK' : 'PIN NOT OK',
162
+ `Authorization Code ${feld('approvedCode')}`,
163
+ `Sequence Number: ${feld('sequenceNumber')}`,
94
164
  ];
95
165
  for (const zeile of inhalt) {
96
166
  if (zeile)
97
167
  zeilen.push(textZeile(zeile, 'center'));
98
168
  }
99
- if (feld('cvm') === '1') {
100
- zeilen.push({ kind: 'space', lines: 2 });
101
- zeilen.push(textZeile('------------------', 'center'));
102
- zeilen.push(textZeile('Unterschrift', 'center'));
169
+ return zeilen;
170
+ }
171
+ function sumupBlock(daten) {
172
+ const feld = (k) => kartenFeld(daten, k);
173
+ const betrag = typeof daten.amount === 'number'
174
+ ? (Number.isInteger(daten.amount) ? formatCents(daten.amount) : daten.amount.toFixed(2).replace('.', ','))
175
+ : '-';
176
+ return [
177
+ textZeile('Sumup Beleg', 'center', true),
178
+ paarZeile('Kartentyp:', feld('cardType') || 'n/a'),
179
+ paarZeile('Kartennummer:', `**** **** **** ${feld('cardLastDigits')}`),
180
+ paarZeile('Zahlungstyp:', feld('paymentType') || 'n/a'),
181
+ paarZeile('Gesamtbetrag:', `${betrag} ${feld('currency')}`.trim()),
182
+ paarZeile('Transaktionscode:', feld('transactionCode') || '-'),
183
+ paarZeile('Modus:', feld('entryMode').toUpperCase()),
184
+ ];
185
+ }
186
+ /**
187
+ * myPOS liefert den Zeitpunkt als `YYMMDDhhmmss` ohne Trenner. Ein Wert, der
188
+ * nicht so aussieht, wird UNVERAENDERT durchgereicht statt zerschnitten: eine
189
+ * halb geratene Uhrzeit auf einem Beleg ist schlimmer als ein roher Wert.
190
+ */
191
+ function myposZeitpunkt(wert) {
192
+ const t = /^(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/.exec(wert);
193
+ if (!t)
194
+ return wert;
195
+ return `${t[3]}.${t[2]}.20${t[1]} ${t[4]}:${t[5]}:${t[6]}`;
196
+ }
197
+ function myposBlock(daten) {
198
+ const feld = (k) => kartenFeld(daten, k);
199
+ const zeilen = [
200
+ textZeile('MyPos Beleg', 'center', true),
201
+ paarZeile('TERMINAL ID:', feld('TID') || '-'),
202
+ paarZeile('DATUM:', myposZeitpunkt(feld('date_time'))),
203
+ ];
204
+ if (feld('application_name'))
205
+ zeilen.push(textZeile(feld('application_name'), 'center', true));
206
+ zeilen.push(paarZeile('KARTE:', feld('pan') || '-'));
207
+ if (daten.signature_required === true)
208
+ zeilen.push(...unterschriftsfeld());
209
+ zeilen.push(paarZeile('STAN:', feld('STAN') ? feld('STAN').padStart(6, '0') : '-'));
210
+ zeilen.push(paarZeile('AUTH. CODE:', feld('authorization_code') || '-'));
211
+ zeilen.push(paarZeile('RRN:', feld('reference_number') || '-'));
212
+ zeilen.push(paarZeile('AID:', feld('AID') || '-'));
213
+ return zeilen;
214
+ }
215
+ const STRIPE_KARTENART = {
216
+ debit: 'Debitkarte',
217
+ credit: 'Kreditkarte',
218
+ prepaid: 'Prepaid-Karte',
219
+ };
220
+ const STRIPE_WALLET = {
221
+ apple_pay: 'Apple Pay',
222
+ google_pay: 'Google Pay',
223
+ };
224
+ /** EPS-Bank-Slug (`bank_austria`) -> Anzeigename (`Bank Austria`). */
225
+ function stripeEpsBank(slug) {
226
+ return slug.split('_').filter(Boolean)
227
+ .map((w) => w[0].toUpperCase() + w.slice(1)).join(' ');
228
+ }
229
+ function stripeMarkenZeile(daten) {
230
+ const teile = [];
231
+ if (daten.cardBrand != null)
232
+ teile.push(String(daten.cardBrand));
233
+ const art = STRIPE_KARTENART[String(daten.cardFunding)];
234
+ if (art)
235
+ teile.push(art);
236
+ let zeile = teile.join(' ');
237
+ if (daten.wallet != null) {
238
+ const wallet = STRIPE_WALLET[String(daten.wallet)] ?? String(daten.wallet);
239
+ zeile = zeile ? `${zeile} (${wallet})` : `(${wallet})`;
240
+ }
241
+ return zeile;
242
+ }
243
+ /**
244
+ * Stripe-Zahlzeitpunkt: Sekunden seit Epoche, gedruckt in **Wiener** Zeit.
245
+ * Ueber `toViennaWallClock`, nicht ueber die lokale Zeitzone -- ein Beleg
246
+ * traegt Ortszeit des Betriebs, nicht die des Geraets, das ihn oeffnet.
247
+ */
248
+ function stripeZeitpunkt(sekunden) {
249
+ const t = toViennaWallClock(new Date(sekunden * 1000));
250
+ const zwei = (n) => String(n).padStart(2, '0');
251
+ return `${zwei(t.day)}.${zwei(t.month)}.${t.year} ${zwei(t.hour)}:${zwei(t.minute)}`;
252
+ }
253
+ /** Zwilling von `stripeReceiptLines` (print_paper.dart). */
254
+ export function stripeReceiptLines(daten, cardPaymentId) {
255
+ const zeilen = [];
256
+ const art = daten.paymentMethodType == null ? null : String(daten.paymentMethodType);
257
+ if (art === 'card') {
258
+ const marke = stripeMarkenZeile(daten);
259
+ if (marke)
260
+ zeilen.push(marke);
261
+ if (daten.cardLastDigits != null)
262
+ zeilen.push(`**** **** **** ${daten.cardLastDigits}`);
263
+ if (daten.threeDSecure === 'authenticated')
264
+ zeilen.push('3-D Secure: ja');
265
+ }
266
+ else if (art === 'eps') {
267
+ if (daten.epsBank != null)
268
+ zeilen.push(`EPS - ${stripeEpsBank(String(daten.epsBank))}`);
269
+ }
270
+ else if (art != null) {
271
+ zeilen.push(art.toUpperCase());
272
+ }
273
+ if (typeof daten.amount === 'number' && Number.isInteger(daten.amount)) {
274
+ const waehrung = daten.currency == null ? 'EUR' : String(daten.currency).toUpperCase();
275
+ zeilen.push(`Gesamtbetrag ${formatCents(daten.amount)} ${waehrung}`);
276
+ }
277
+ if (typeof daten.paidAt === 'number' && Number.isInteger(daten.paidAt)) {
278
+ zeilen.push(`Bezahlt: ${stripeZeitpunkt(daten.paidAt)}`);
279
+ }
280
+ if (daten.statementDescriptor != null)
281
+ zeilen.push(`Abrechnung: ${daten.statementDescriptor}`);
282
+ if (cardPaymentId != null)
283
+ zeilen.push(`Referenz: ${cardPaymentId}`);
284
+ return zeilen;
285
+ }
286
+ function stripeBlock(daten, cardPaymentId) {
287
+ const zeilen = [textZeile('Online-Zahlung (Stripe)', 'center', true)];
288
+ for (const zeile of stripeReceiptLines(daten, cardPaymentId)) {
289
+ zeilen.push(textZeile(zeile, 'center'));
103
290
  }
104
- zeilen.push({ kind: 'space', lines: 1 });
105
291
  return zeilen;
106
292
  }
293
+ /**
294
+ * Der Kartenzahlungsblock des Belegs -- fuer JEDEN Anbieter, den das Backend
295
+ * kennt. Ohne `cardPaymentData` bleibt der Block weg; ein unbekannter Anbieter
296
+ * ebenfalls, still und ohne Fehler: ein Beleg muss sich immer zeigen lassen.
297
+ */
298
+ function kartenblock(receipt) {
299
+ const daten = receipt.cardPaymentData;
300
+ if (daten == null)
301
+ return [];
302
+ const zeilen = (() => {
303
+ switch (receipt.creditCardProvider) {
304
+ case 'hobexHps':
305
+ case 'hobexCloudApi':
306
+ return hobexBlock(daten);
307
+ case 'gpTomAndroid':
308
+ case 'gpTomIos':
309
+ return gpTomBlock(daten);
310
+ case 'sumup':
311
+ return sumupBlock(daten);
312
+ case 'myposPro':
313
+ return myposBlock(daten);
314
+ case 'stripe':
315
+ return stripeBlock(daten, receipt.cardPaymentId ?? null);
316
+ default:
317
+ return [];
318
+ }
319
+ })();
320
+ if (zeilen.length === 0)
321
+ return [];
322
+ // Eine Leerzeile hinter JEDEM Block, nicht nur hinter manchen. Das Vorbild
323
+ // ist hier uneinheitlich (nur `_sumup` setzt am Ende ein `addFeed()`), was
324
+ // den Abstand zur Fusszeile vom Anbieter abhaengig machte. Die Leerzeile
325
+ // gehoert aber zum Blatt, nicht zum Terminal.
326
+ return [...zeilen, { kind: 'space', lines: 1 }];
327
+ }
107
328
  function zahlungsartText(wert) {
108
329
  if (wert != null && typeof wert === 'object') {
109
330
  return wert.label;
@@ -697,7 +918,7 @@ export function buildReceiptLayout(receipt, company, options = {}) {
697
918
  lines.push({ kind: 'qr', data: receipt.qr });
698
919
  lines.push({ kind: 'space', lines: 1 });
699
920
  // --- Kartenzahlungsblock (Hobex) — wie im Vorbild UNTER dem QR-Code.
700
- lines.push(...hobexKartenblock(receipt));
921
+ lines.push(...kartenblock(receipt));
701
922
  // --- Dankestext und Fusszeilen
702
923
  if (company.thanksMessage.length > 0) {
703
924
  lines.push({ kind: 'space', lines: 1 });
@@ -0,0 +1,44 @@
1
+ {
2
+ "company": {
3
+ "companyName": "Bäckerei Muster",
4
+ "street": "Hauptplatz 1",
5
+ "zip": "4830",
6
+ "city": "Hallstatt",
7
+ "phone": "+43 6134 12345",
8
+ "uid": "ATU12345678",
9
+ "taxnr": "",
10
+ "isSmallBusiness": false,
11
+ "footer1": "Vielen Dank für Ihren Einkauf",
12
+ "footer2": "www.baeckerei-muster.at",
13
+ "thanksMessage": [],
14
+ "showKreiseckLogo": false
15
+ },
16
+ "receipt": {
17
+ "receiptId": "AT0-KASSE1-66",
18
+ "cashregisterId": "KASSE1",
19
+ "timeStamp": "2026-08-13T10:15:30",
20
+ "items": [
21
+ {
22
+ "name": "Behandlung",
23
+ "quantity": 1,
24
+ "unitPriceCents": 12000,
25
+ "vatRate": 20
26
+ }
27
+ ],
28
+ "vouchers": [],
29
+ "paymentMethod": "creditCard",
30
+ "turnoverCounterAES256ICM": "UMSATZ",
31
+ "signaturePreviousReceipt": "VORGAENGER",
32
+ "certificateSerialNumber": "6F0404F0",
33
+ "receiptType": "standard",
34
+ "sig": "eyJhbGciOiJFUzI1NiJ9.QVQx.SIGNATURWERT",
35
+ "qr": "_R1-AT1_KASSE1_AT0-KASSE1-66_2026-08-13T10:15:30_120,00_0,00_0,00_0,00_0,00_UMSATZ_VORGAENGER_6F0404F0_SIGNATUR",
36
+ "fullReceiptId": "VOLL",
37
+ "customerDetails": [],
38
+ "legalMessage": [],
39
+ "creditCardProvider": "custom"
40
+ },
41
+ "options": {
42
+ "paperSize": "mm80"
43
+ }
44
+ }
@@ -0,0 +1,59 @@
1
+ {
2
+ "company": {
3
+ "companyName": "Bäckerei Muster",
4
+ "street": "Hauptplatz 1",
5
+ "zip": "4830",
6
+ "city": "Hallstatt",
7
+ "phone": "+43 6134 12345",
8
+ "uid": "ATU12345678",
9
+ "taxnr": "",
10
+ "isSmallBusiness": false,
11
+ "footer1": "Vielen Dank für Ihren Einkauf",
12
+ "footer2": "www.baeckerei-muster.at",
13
+ "thanksMessage": [],
14
+ "showKreiseckLogo": false
15
+ },
16
+ "receipt": {
17
+ "receiptId": "AT0-KASSE1-67",
18
+ "cashregisterId": "KASSE1",
19
+ "timeStamp": "2026-08-13T10:15:30",
20
+ "items": [
21
+ {
22
+ "name": "Behandlung",
23
+ "quantity": 1,
24
+ "unitPriceCents": 12000,
25
+ "vatRate": 20
26
+ }
27
+ ],
28
+ "vouchers": [],
29
+ "paymentMethod": "creditCard",
30
+ "turnoverCounterAES256ICM": "UMSATZ",
31
+ "signaturePreviousReceipt": "VORGAENGER",
32
+ "certificateSerialNumber": "6F0404F0",
33
+ "receiptType": "standard",
34
+ "sig": "eyJhbGciOiJFUzI1NiJ9.QVQx.SIGNATURWERT",
35
+ "qr": "_R1-AT1_KASSE1_AT0-KASSE1-67_2026-08-13T10:15:30_120,00_0,00_0,00_0,00_0,00_UMSATZ_VORGAENGER_6F0404F0_SIGNATUR",
36
+ "fullReceiptId": "VOLL",
37
+ "customerDetails": [],
38
+ "legalMessage": [],
39
+ "creditCardProvider": "gpTomIos",
40
+ "cardPaymentData": {
41
+ "batchNumber": 12,
42
+ "externalTransactionID": "TX-9911",
43
+ "terminalID": "T-55",
44
+ "emvAid": "A0000000031010",
45
+ "emvAppLable": "VISA CREDIT",
46
+ "cardDataEntry": "CONTACTLESS",
47
+ "cardNumber": "**** **** **** 4720",
48
+ "currencyCode": "EUR",
49
+ "amount": 12000,
50
+ "pinOk": false,
51
+ "approvedCode": "123456",
52
+ "sequenceNumber": 42,
53
+ "transacitonType": 3
54
+ }
55
+ },
56
+ "options": {
57
+ "paperSize": "mm80"
58
+ }
59
+ }
@@ -0,0 +1,59 @@
1
+ {
2
+ "company": {
3
+ "companyName": "Bäckerei Muster",
4
+ "street": "Hauptplatz 1",
5
+ "zip": "4830",
6
+ "city": "Hallstatt",
7
+ "phone": "+43 6134 12345",
8
+ "uid": "ATU12345678",
9
+ "taxnr": "",
10
+ "isSmallBusiness": false,
11
+ "footer1": "Vielen Dank für Ihren Einkauf",
12
+ "footer2": "www.baeckerei-muster.at",
13
+ "thanksMessage": [],
14
+ "showKreiseckLogo": false
15
+ },
16
+ "receipt": {
17
+ "receiptId": "AT0-KASSE1-61",
18
+ "cashregisterId": "KASSE1",
19
+ "timeStamp": "2026-08-13T10:15:30",
20
+ "items": [
21
+ {
22
+ "name": "Behandlung",
23
+ "quantity": 1,
24
+ "unitPriceCents": 12000,
25
+ "vatRate": 20
26
+ }
27
+ ],
28
+ "vouchers": [],
29
+ "paymentMethod": "creditCard",
30
+ "turnoverCounterAES256ICM": "UMSATZ",
31
+ "signaturePreviousReceipt": "VORGAENGER",
32
+ "certificateSerialNumber": "6F0404F0",
33
+ "receiptType": "standard",
34
+ "sig": "eyJhbGciOiJFUzI1NiJ9.QVQx.SIGNATURWERT",
35
+ "qr": "_R1-AT1_KASSE1_AT0-KASSE1-61_2026-08-13T10:15:30_120,00_0,00_0,00_0,00_0,00_UMSATZ_VORGAENGER_6F0404F0_SIGNATUR",
36
+ "fullReceiptId": "VOLL",
37
+ "customerDetails": [],
38
+ "legalMessage": [],
39
+ "creditCardProvider": "gpTomAndroid",
40
+ "cardPaymentData": {
41
+ "batchNumber": 12,
42
+ "externalTransactionID": "TX-9911",
43
+ "terminalID": "T-55",
44
+ "emvAid": "A0000000031010",
45
+ "emvAppLable": "VISA CREDIT",
46
+ "cardDataEntry": "CONTACTLESS",
47
+ "cardNumber": "**** **** **** 4720",
48
+ "currencyCode": "EUR",
49
+ "amount": 12000,
50
+ "pinOk": true,
51
+ "approvedCode": "123456",
52
+ "sequenceNumber": 42,
53
+ "transactionType": 1
54
+ }
55
+ },
56
+ "options": {
57
+ "paperSize": "mm80"
58
+ }
59
+ }
@@ -0,0 +1,54 @@
1
+ {
2
+ "company": {
3
+ "companyName": "Bäckerei Muster",
4
+ "street": "Hauptplatz 1",
5
+ "zip": "4830",
6
+ "city": "Hallstatt",
7
+ "phone": "+43 6134 12345",
8
+ "uid": "ATU12345678",
9
+ "taxnr": "",
10
+ "isSmallBusiness": false,
11
+ "footer1": "Vielen Dank für Ihren Einkauf",
12
+ "footer2": "www.baeckerei-muster.at",
13
+ "thanksMessage": [],
14
+ "showKreiseckLogo": false
15
+ },
16
+ "receipt": {
17
+ "receiptId": "AT0-KASSE1-68",
18
+ "cashregisterId": "KASSE1",
19
+ "timeStamp": "2026-08-13T10:15:30",
20
+ "items": [
21
+ {
22
+ "name": "Behandlung",
23
+ "quantity": 1,
24
+ "unitPriceCents": 12000,
25
+ "vatRate": 20
26
+ }
27
+ ],
28
+ "vouchers": [],
29
+ "paymentMethod": "creditCard",
30
+ "turnoverCounterAES256ICM": "UMSATZ",
31
+ "signaturePreviousReceipt": "VORGAENGER",
32
+ "certificateSerialNumber": "6F0404F0",
33
+ "receiptType": "standard",
34
+ "sig": "eyJhbGciOiJFUzI1NiJ9.QVQx.SIGNATURWERT",
35
+ "qr": "_R1-AT1_KASSE1_AT0-KASSE1-68_2026-08-13T10:15:30_120,00_0,00_0,00_0,00_0,00_UMSATZ_VORGAENGER_6F0404F0_SIGNATUR",
36
+ "fullReceiptId": "VOLL",
37
+ "customerDetails": [],
38
+ "legalMessage": [],
39
+ "creditCardProvider": "hobexCloudApi",
40
+ "cardPaymentData": {
41
+ "date": "13.08.2026 10:15",
42
+ "tid": "12345678",
43
+ "no": "004711",
44
+ "type": "Kauf",
45
+ "cardBrand": "VISA",
46
+ "cardNumber": "************4720",
47
+ "responseCode": "00",
48
+ "cvm": "0"
49
+ }
50
+ },
51
+ "options": {
52
+ "paperSize": "mm80"
53
+ }
54
+ }
@@ -0,0 +1,54 @@
1
+ {
2
+ "company": {
3
+ "companyName": "Bäckerei Muster",
4
+ "street": "Hauptplatz 1",
5
+ "zip": "4830",
6
+ "city": "Hallstatt",
7
+ "phone": "+43 6134 12345",
8
+ "uid": "ATU12345678",
9
+ "taxnr": "",
10
+ "isSmallBusiness": false,
11
+ "footer1": "Vielen Dank für Ihren Einkauf",
12
+ "footer2": "www.baeckerei-muster.at",
13
+ "thanksMessage": [],
14
+ "showKreiseckLogo": false
15
+ },
16
+ "receipt": {
17
+ "receiptId": "AT0-KASSE1-60",
18
+ "cashregisterId": "KASSE1",
19
+ "timeStamp": "2026-08-13T10:15:30",
20
+ "items": [
21
+ {
22
+ "name": "Behandlung",
23
+ "quantity": 1,
24
+ "unitPriceCents": 12000,
25
+ "vatRate": 20
26
+ }
27
+ ],
28
+ "vouchers": [],
29
+ "paymentMethod": "creditCard",
30
+ "turnoverCounterAES256ICM": "UMSATZ",
31
+ "signaturePreviousReceipt": "VORGAENGER",
32
+ "certificateSerialNumber": "6F0404F0",
33
+ "receiptType": "standard",
34
+ "sig": "eyJhbGciOiJFUzI1NiJ9.QVQx.SIGNATURWERT",
35
+ "qr": "_R1-AT1_KASSE1_AT0-KASSE1-60_2026-08-13T10:15:30_120,00_0,00_0,00_0,00_0,00_UMSATZ_VORGAENGER_6F0404F0_SIGNATUR",
36
+ "fullReceiptId": "VOLL",
37
+ "customerDetails": [],
38
+ "legalMessage": [],
39
+ "creditCardProvider": "hobexHps",
40
+ "cardPaymentData": {
41
+ "date": "13.08.2026 10:15",
42
+ "tid": "12345678",
43
+ "no": "004711",
44
+ "type": "Kauf",
45
+ "cardBrand": "VISA",
46
+ "cardNumber": "************4720_2810",
47
+ "responseCode": "00",
48
+ "cvm": "1"
49
+ }
50
+ },
51
+ "options": {
52
+ "paperSize": "mm80"
53
+ }
54
+ }
@@ -0,0 +1,55 @@
1
+ {
2
+ "company": {
3
+ "companyName": "Bäckerei Muster",
4
+ "street": "Hauptplatz 1",
5
+ "zip": "4830",
6
+ "city": "Hallstatt",
7
+ "phone": "+43 6134 12345",
8
+ "uid": "ATU12345678",
9
+ "taxnr": "",
10
+ "isSmallBusiness": false,
11
+ "footer1": "Vielen Dank für Ihren Einkauf",
12
+ "footer2": "www.baeckerei-muster.at",
13
+ "thanksMessage": [],
14
+ "showKreiseckLogo": false
15
+ },
16
+ "receipt": {
17
+ "receiptId": "AT0-KASSE1-63",
18
+ "cashregisterId": "KASSE1",
19
+ "timeStamp": "2026-08-13T10:15:30",
20
+ "items": [
21
+ {
22
+ "name": "Behandlung",
23
+ "quantity": 1,
24
+ "unitPriceCents": 12000,
25
+ "vatRate": 20
26
+ }
27
+ ],
28
+ "vouchers": [],
29
+ "paymentMethod": "creditCard",
30
+ "turnoverCounterAES256ICM": "UMSATZ",
31
+ "signaturePreviousReceipt": "VORGAENGER",
32
+ "certificateSerialNumber": "6F0404F0",
33
+ "receiptType": "standard",
34
+ "sig": "eyJhbGciOiJFUzI1NiJ9.QVQx.SIGNATURWERT",
35
+ "qr": "_R1-AT1_KASSE1_AT0-KASSE1-63_2026-08-13T10:15:30_120,00_0,00_0,00_0,00_0,00_UMSATZ_VORGAENGER_6F0404F0_SIGNATUR",
36
+ "fullReceiptId": "VOLL",
37
+ "customerDetails": [],
38
+ "legalMessage": [],
39
+ "creditCardProvider": "myposPro",
40
+ "cardPaymentData": {
41
+ "TID": "10203040",
42
+ "date_time": "260813101530",
43
+ "application_name": "MASTERCARD",
44
+ "pan": "**** **** **** 4720",
45
+ "signature_required": true,
46
+ "STAN": 815,
47
+ "authorization_code": "123456",
48
+ "reference_number": "622512345678",
49
+ "AID": "A0000000041010"
50
+ }
51
+ },
52
+ "options": {
53
+ "paperSize": "mm80"
54
+ }
55
+ }