@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.
- package/CHANGELOG.md +47 -0
- package/dist/cjs/receipt/layout.d.ts +11 -5
- package/dist/cjs/receipt/layout.js +248 -26
- package/dist/esm/receipt/layout.d.ts +11 -5
- package/dist/esm/receipt/layout.js +247 -26
- package/fixtures/belege/karte-eigener.json +44 -0
- package/fixtures/belege/karte-gptom-ios.json +59 -0
- package/fixtures/belege/karte-gptom.json +59 -0
- package/fixtures/belege/karte-hobex-cloud.json +54 -0
- package/fixtures/belege/karte-hobex-hps.json +54 -0
- package/fixtures/belege/karte-mypos.json +55 -0
- package/fixtures/belege/karte-stripe-eps.json +52 -0
- package/fixtures/belege/karte-stripe.json +57 -0
- package/fixtures/belege/karte-sumup.json +53 -0
- package/fixtures/erwartet/karte-eigener.grid32.txt +22 -0
- package/fixtures/erwartet/karte-eigener.grid48.txt +22 -0
- package/fixtures/erwartet/karte-eigener.lines.json +216 -0
- package/fixtures/erwartet/karte-gptom-ios.grid32.txt +34 -0
- package/fixtures/erwartet/karte-gptom-ios.grid48.txt +34 -0
- package/fixtures/erwartet/karte-gptom-ios.lines.json +286 -0
- package/fixtures/erwartet/karte-gptom.grid32.txt +34 -0
- package/fixtures/erwartet/karte-gptom.grid48.txt +34 -0
- package/fixtures/erwartet/karte-gptom.lines.json +286 -0
- package/fixtures/erwartet/karte-hobex-cloud.grid32.txt +29 -0
- package/fixtures/erwartet/karte-hobex-cloud.grid48.txt +29 -0
- package/fixtures/erwartet/karte-hobex-cloud.lines.json +256 -0
- package/fixtures/erwartet/karte-hobex-hps.grid32.txt +33 -0
- package/fixtures/erwartet/karte-hobex-hps.grid48.txt +33 -0
- package/fixtures/erwartet/karte-hobex-hps.lines.json +272 -0
- package/fixtures/erwartet/karte-mypos.grid32.txt +38 -0
- package/fixtures/erwartet/karte-mypos.grid48.txt +36 -0
- package/fixtures/erwartet/karte-mypos.lines.json +353 -0
- package/fixtures/erwartet/karte-stripe-eps.grid32.txt +28 -0
- package/fixtures/erwartet/karte-stripe-eps.grid48.txt +28 -0
- package/fixtures/erwartet/karte-stripe-eps.lines.json +250 -0
- package/fixtures/erwartet/karte-stripe.grid32.txt +31 -0
- package/fixtures/erwartet/karte-stripe.grid48.txt +31 -0
- package/fixtures/erwartet/karte-stripe.lines.json +268 -0
- package/fixtures/erwartet/karte-sumup.grid32.txt +32 -0
- package/fixtures/erwartet/karte-sumup.grid48.txt +30 -0
- package/fixtures/erwartet/karte-sumup.lines.json +316 -0
- package/fixtures/hobex-hps-codes.json +1 -1
- package/fixtures/kasse-texte.json +1 -1
- package/fixtures/manifest.json +54 -0
- package/fixtures/oberflaeche.json +1 -1
- 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
|
|
75
|
-
const
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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(...
|
|
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
|
+
}
|