@kreiseck/kasseneck-api 1.0.0-rc.2 → 1.0.0-rc.3
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 +22 -1
- package/README.md +5 -1
- package/dist/cjs/client/receipts.d.ts +10 -3
- package/dist/cjs/client/receipts.js +11 -8
- package/dist/cjs/models/cashregister.d.ts +14 -8
- package/dist/cjs/models/cashregister.js +4 -4
- package/dist/cjs/pos/client.d.ts +6 -1
- package/dist/cjs/pos/client.js +15 -3
- package/dist/cjs/pos/drucker.js +22 -3
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/client/receipts.d.ts +10 -3
- package/dist/esm/client/receipts.js +11 -8
- package/dist/esm/models/cashregister.d.ts +14 -8
- package/dist/esm/models/cashregister.js +4 -4
- package/dist/esm/pos/client.d.ts +6 -1
- package/dist/esm/pos/client.js +15 -3
- package/dist/esm/pos/drucker.js +22 -3
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/fixtures/hobex-hps-codes.json +1 -1
- package/fixtures/invoice-api.schema.json +1 -1
- package/fixtures/invoice-texts.json +1 -1
- package/fixtures/pos-texts.json +1 -1
- package/fixtures/surface.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -126,6 +126,27 @@ an upgrade as long as `/v1` is served.
|
|
|
126
126
|
Reason: an app that read `'rejected'` could charge or refund a card twice;
|
|
127
127
|
a silent resend below the package does the same without any error. Same
|
|
128
128
|
change as in the Dart twin `kasseneck_api` (no `RetryClient`).
|
|
129
|
+
- **Findings of the Dart twin (1.0.0-rc.3).** `listMyCashregisters` reads
|
|
130
|
+
the start receipt under `onboarding.start_receipt_created`/`_transmitted`
|
|
131
|
+
(`_at`) as `/v3` sends it; rc.1 and rc.2 read the internal
|
|
132
|
+
`startbeleg_*` names and reported every register as having no start
|
|
133
|
+
receipt (`CashregisterOnboardingPayload` changes accordingly). The fields
|
|
134
|
+
of `CashregisterOnboarding` are English now as well: `startbelegCreated`
|
|
135
|
+
is `startReceiptCreated`, `startbelegTransmitted` is
|
|
136
|
+
`startReceiptTransmitted`, `startbelegCreatedAt` is `startReceiptCreatedAt`,
|
|
137
|
+
`startbelegTransmittedAt` is `startReceiptTransmittedAt`; the German-name
|
|
138
|
+
guard no longer exempts `startbeleg`.
|
|
139
|
+
`sendReceiptEmail` reads its success reply leniently: without `to` it
|
|
140
|
+
returns the address you sent, without `at` it returns `at: null`
|
|
141
|
+
(`SendReceiptEmailResult.at` is `string | null`); throwing there would
|
|
142
|
+
invite a second email. `listMyPrinters` without `data.printers` and
|
|
143
|
+
`createPrintJob`/`getPrintJob` without `data.jobId` throw a
|
|
144
|
+
`KasseneckValidationError` (`scope: 'response'`) instead of returning an
|
|
145
|
+
empty list or an empty id: "no printer yet" must not look like a broken
|
|
146
|
+
reply, and a job without an id cannot be polled, so the cashier would print
|
|
147
|
+
again. `setMyRegisterDeviceSettings` takes `shortcuts` only as the whole map
|
|
148
|
+
of known actions (as `posSettingsChanges` produces it): the server checks
|
|
149
|
+
keys bound twice only within the map it receives.
|
|
129
150
|
- **Strict validation before sending.** The 0.x payment fields
|
|
130
151
|
(`paymentMethod`, `paymentMethodFromServer`, `creditCardProvider`,
|
|
131
152
|
`cardPaymentId`, `cardPaymentData`) throw, also from plain JavaScript.
|
|
@@ -252,7 +273,7 @@ texts are English: `storno.ergebnis_unklar` is `cancellation.outcome_unknown`,
|
|
|
252
273
|
`tax.intra_community_supply.title`. Every part is lower case with underscores,
|
|
253
274
|
only country codes stay upper case (`country.AT`). Placeholders are English
|
|
254
275
|
too: `{betrag}` is `{amount}`, `{grund}` is `{reason}`, `{sekunden}` is
|
|
255
|
-
`{seconds}`, `{uid}` is `{vatId}`, and so on for
|
|
276
|
+
`{seconds}`, `{uid}` is `{vatId}`, and so on for 25 of 30 names; pass the
|
|
256
277
|
values under the new names (`messageText('checkout.locked', { reason })`). An
|
|
257
278
|
old name throws as a missing value. `ERROR_RULES` entries use
|
|
258
279
|
`kind`/`behavior`/`key` with the kinds `api`, `plain_text`, `timeout`,
|
package/README.md
CHANGED
|
@@ -615,10 +615,14 @@ const confirmation = await api.sendReceiptEmail({
|
|
|
615
615
|
language: 'de', // optional; the backend currently only uses 'de'
|
|
616
616
|
});
|
|
617
617
|
confirmation.to; // address as the backend logged it (trimmed, lower case)
|
|
618
|
-
confirmation.at; // time, ISO with Vienna offset
|
|
618
|
+
confirmation.at; // time, ISO with Vienna offset, or null
|
|
619
619
|
confirmation.via; // 'own' | 'platform' | 'platform_fallback' | null
|
|
620
620
|
```
|
|
621
621
|
|
|
622
|
+
A success response means the email has gone out. If it lacks `to` or `at`,
|
|
623
|
+
the call still succeeds: `to` falls back to the address you sent and `at` is
|
|
624
|
+
`null`. Throwing there would invite sending the email a second time.
|
|
625
|
+
|
|
622
626
|
The email contains a **link to the public receipt page**, not a PDF
|
|
623
627
|
attachment: the receipt page uses the same line model as screen and printed
|
|
624
628
|
receipt and offers a PDF there. The receipt itself stays untouched (BAO § 131,
|
|
@@ -315,10 +315,17 @@ export interface SendReceiptEmailOptions {
|
|
|
315
315
|
}
|
|
316
316
|
/** Was der Versand bestaetigt (Backend: beleg-mail-endpoints.js). */
|
|
317
317
|
export interface SendReceiptEmailResult {
|
|
318
|
-
/**
|
|
318
|
+
/**
|
|
319
|
+
* Adresse in der Form, in der das Backend sie protokolliert hat (getrimmt,
|
|
320
|
+
* klein). Nennt die Antwort keine, die gesendete (getrimmte) Adresse.
|
|
321
|
+
*/
|
|
319
322
|
to: string;
|
|
320
|
-
/**
|
|
321
|
-
|
|
323
|
+
/**
|
|
324
|
+
* Zeitpunkt des Versands, ISO mit Wiener Zonenoffset
|
|
325
|
+
* (`2026-09-11T14:05:00+02:00`). `null`, wenn die Antwort keinen nennt: der
|
|
326
|
+
* Versand ist trotzdem bestaetigt.
|
|
327
|
+
*/
|
|
328
|
+
at: string | null;
|
|
322
329
|
/**
|
|
323
330
|
* Versandweg: `own` (Postfach des Betriebs), `platform` oder
|
|
324
331
|
* `platform_fallback` ([RECEIPT_EMAIL_VIAS]). `null`, wenn die Antwort ihn
|
|
@@ -395,14 +395,17 @@ async function sendReceiptEmail(transport, options) {
|
|
|
395
395
|
if (options.language !== undefined && options.language !== '')
|
|
396
396
|
params.language = options.language;
|
|
397
397
|
const daten = await transport('sendReceiptEmail', params);
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
398
|
+
// Nachsichtig gelesen (wie der Dart-Zwilling): eine Erfolgsantwort heisst,
|
|
399
|
+
// die Mail ist schon verschickt. Ein Fehler wegen eines fehlenden
|
|
400
|
+
// Antwortfelds luede zum zweiten Versand ein; also zurueck, was da ist.
|
|
401
|
+
const gemeldet = daten?.to;
|
|
402
|
+
const zeit = daten?.at;
|
|
403
|
+
const via = index_js_2.RECEIPT_EMAIL_VIAS.includes(daten?.via) ? daten.via : null;
|
|
404
|
+
return {
|
|
405
|
+
to: typeof gemeldet === 'string' && gemeldet.trim() !== '' ? gemeldet : to,
|
|
406
|
+
at: typeof zeit === 'string' && zeit !== '' ? zeit : null,
|
|
407
|
+
via,
|
|
408
|
+
};
|
|
406
409
|
}
|
|
407
410
|
/**
|
|
408
411
|
* Prueft die Gutschein-Kombination eines Belegs und liefert den ersten
|
|
@@ -45,11 +45,11 @@ export interface Cashregister {
|
|
|
45
45
|
*/
|
|
46
46
|
export interface CashregisterOnboarding {
|
|
47
47
|
cashboxRegistered: boolean;
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
startReceiptCreated: boolean;
|
|
49
|
+
startReceiptTransmitted: boolean;
|
|
50
50
|
cashboxRegisteredAt?: Date;
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
startReceiptCreatedAt?: Date;
|
|
52
|
+
startReceiptTransmittedAt?: Date;
|
|
53
53
|
}
|
|
54
54
|
/** Nutzlast-Form, die dieses Paket liest — die Feldnamen von `listMyCashregisters`. */
|
|
55
55
|
export interface CashregisterPayload {
|
|
@@ -61,13 +61,19 @@ export interface CashregisterPayload {
|
|
|
61
61
|
token?: string | null;
|
|
62
62
|
onboarding?: CashregisterOnboardingPayload | null;
|
|
63
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* `onboarding` am Draht `/v3` (fixtures/v3/antworten/kasse.json): der
|
|
66
|
+
* Startbeleg heisst dort `start_receipt_*`. Die inneren Namen
|
|
67
|
+
* `startbeleg_*` sendet nur `/v1`; wer sie hier laese, meldete jede Kasse
|
|
68
|
+
* als „Startbeleg fehlt“.
|
|
69
|
+
*/
|
|
64
70
|
export interface CashregisterOnboardingPayload {
|
|
65
71
|
cashbox_registered?: boolean | null;
|
|
66
|
-
|
|
67
|
-
|
|
72
|
+
start_receipt_created?: boolean | null;
|
|
73
|
+
start_receipt_transmitted?: boolean | null;
|
|
68
74
|
cashbox_registered_at?: string | null;
|
|
69
|
-
|
|
70
|
-
|
|
75
|
+
start_receipt_created_at?: string | null;
|
|
76
|
+
start_receipt_transmitted_at?: string | null;
|
|
71
77
|
}
|
|
72
78
|
/**
|
|
73
79
|
* Liest eine Kasse aus der Antwort. `id` gewinnt aus der Nutzlast, faellt aber
|
|
@@ -18,11 +18,11 @@ function fromCashregisterPayload(payload, id) {
|
|
|
18
18
|
...(payload.signature_id ? { signatureId: payload.signature_id } : {}),
|
|
19
19
|
onboarding: {
|
|
20
20
|
cashboxRegistered: ob.cashbox_registered === true,
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
startReceiptCreated: ob.start_receipt_created === true,
|
|
22
|
+
startReceiptTransmitted: ob.start_receipt_transmitted === true,
|
|
23
23
|
...zeitfeld('cashboxRegisteredAt', ob.cashbox_registered_at),
|
|
24
|
-
...zeitfeld('
|
|
25
|
-
...zeitfeld('
|
|
24
|
+
...zeitfeld('startReceiptCreatedAt', ob.start_receipt_created_at),
|
|
25
|
+
...zeitfeld('startReceiptTransmittedAt', ob.start_receipt_transmitted_at),
|
|
26
26
|
},
|
|
27
27
|
};
|
|
28
28
|
}
|
package/dist/cjs/pos/client.d.ts
CHANGED
|
@@ -11,7 +11,12 @@ export declare function posSettingsFromWire(data: {
|
|
|
11
11
|
} | null | undefined): PosSettings;
|
|
12
12
|
/** Betriebsweite Einstellungen schreiben (Recht `layout`); liefert den gemischten Stand. */
|
|
13
13
|
export declare function setMyPosSettings(transport: InternerTransport, business: Partial<PosBusinessSettings>): Promise<PosBusinessSettings>;
|
|
14
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Geraete-Einstellungen schreiben (Recht `layout`); liefert den gemischten
|
|
16
|
+
* Stand. `shortcuts` nur als ganze Karte aller bekannten Aktionen
|
|
17
|
+
* ([posSettingsChanges] liefert sie bei jeder Tastenaenderung), sonst wirft
|
|
18
|
+
* der Aufruf vor dem Senden.
|
|
19
|
+
*/
|
|
15
20
|
export declare function setMyRegisterDeviceSettings(transport: InternerTransport, deviceId: string, device: Partial<PosDeviceSettings>): Promise<PosDeviceSettings>;
|
|
16
21
|
/** Eingabe von [setMyPosLogo]: ein Bild als Data-URL (PNG, JPEG, SVG) oder das Entfernen. */
|
|
17
22
|
export type SetMyPosLogoOptions = {
|
package/dist/cjs/pos/client.js
CHANGED
|
@@ -57,7 +57,12 @@ async function setMyPosSettings(transport, business) {
|
|
|
57
57
|
const daten = await transport(name, { business });
|
|
58
58
|
return (0, settings_js_1.mergePosSettings)(settings_js_1.POS_BUSINESS_DEFAULTS, objekt(daten?.business));
|
|
59
59
|
}
|
|
60
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* Geraete-Einstellungen schreiben (Recht `layout`); liefert den gemischten
|
|
62
|
+
* Stand. `shortcuts` nur als ganze Karte aller bekannten Aktionen
|
|
63
|
+
* ([posSettingsChanges] liefert sie bei jeder Tastenaenderung), sonst wirft
|
|
64
|
+
* der Aufruf vor dem Senden.
|
|
65
|
+
*/
|
|
61
66
|
async function setMyRegisterDeviceSettings(transport, deviceId, device) {
|
|
62
67
|
const name = 'setMyRegisterDeviceSettings';
|
|
63
68
|
if (typeof deviceId !== 'string' || deviceId.trim() === '') {
|
|
@@ -77,8 +82,15 @@ async function setMyRegisterDeviceSettings(transport, deviceId, device) {
|
|
|
77
82
|
throw new errors_js_1.KasseneckValidationError(name, `device.shortcuts.${aktion}: unbekannte Aktion`, 'request');
|
|
78
83
|
}
|
|
79
84
|
}
|
|
80
|
-
//
|
|
81
|
-
//
|
|
85
|
+
// Nur die ganze Karte: der Server prueft Doppelbelegungen nur in der
|
|
86
|
+
// gesendeten Karte, eine halbe (`{cash: ['Mod+K']}`) liesse eine
|
|
87
|
+
// Doppelbelegung mit einer gespeicherten Taste durch. posSettingsChanges
|
|
88
|
+
// liefert bei jeder Tastenaenderung die ganze Karte.
|
|
89
|
+
const fehlt = settings_js_1.POS_SHORTCUT_ACTIONS.filter((a) => karte[a] === undefined);
|
|
90
|
+
if (fehlt.length > 0) {
|
|
91
|
+
throw new errors_js_1.KasseneckValidationError(name, `device.shortcuts: ganze Karte senden (posSettingsChanges), es fehlen ${fehlt.join(', ')}`, 'request');
|
|
92
|
+
}
|
|
93
|
+
// Doppelbelegung in der ganzen Karte, also in der ganzen Belegung.
|
|
82
94
|
const konflikt = (0, settings_js_1.posShortcutConflict)(karte);
|
|
83
95
|
if (konflikt) {
|
|
84
96
|
throw new errors_js_1.KasseneckValidationError(name, `device.shortcuts.${konflikt.action}: Taste ${konflikt.key} schon belegt (${konflikt.heldBy})`, 'request');
|
package/dist/cjs/pos/drucker.js
CHANGED
|
@@ -5,6 +5,7 @@ exports.isPrintJobFinished = isPrintJobFinished;
|
|
|
5
5
|
exports.listMyPrinters = listMyPrinters;
|
|
6
6
|
exports.createPrintJob = createPrintJob;
|
|
7
7
|
exports.getPrintJob = getPrintJob;
|
|
8
|
+
const errors_js_1 = require("../client/errors.js");
|
|
8
9
|
const index_js_1 = require("../printing/index.js");
|
|
9
10
|
/** Stand eines Druckjobs (Katalog `DRUCKJOB`). */
|
|
10
11
|
exports.PRINT_JOB_STATUSES = ['pending', 'sent', 'printed', 'failed', 'expired'];
|
|
@@ -29,9 +30,27 @@ const STATUS = new Set(exports.PRINT_JOB_STATUSES);
|
|
|
29
30
|
function status(v) {
|
|
30
31
|
return typeof v === 'string' && STATUS.has(v) ? v : 'unknown';
|
|
31
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Die Kennung eines Jobs aus der Antwort. Ohne sie kann niemand den Job
|
|
35
|
+
* abfragen; ein leerer Text waere ein angeblich angelegter Job, und der
|
|
36
|
+
* Kassier druckte ein zweites Mal.
|
|
37
|
+
*/
|
|
38
|
+
function jobKennung(name, d) {
|
|
39
|
+
const id = d?.jobId;
|
|
40
|
+
if (typeof id !== 'string' || id === '') {
|
|
41
|
+
throw new errors_js_1.KasseneckValidationError(name, 'Antwort enthaelt keine Kennung (data.jobId fehlt)', 'response');
|
|
42
|
+
}
|
|
43
|
+
return id;
|
|
44
|
+
}
|
|
32
45
|
async function listMyPrinters(transport) {
|
|
33
46
|
const daten = await transport('listMyPrinters', {});
|
|
34
|
-
|
|
47
|
+
const liste = daten?.printers;
|
|
48
|
+
if (!Array.isArray(liste)) {
|
|
49
|
+
// Keine Liste ist etwas anderes als eine leere Liste: „noch kein Drucker“
|
|
50
|
+
// darf nicht aussehen wie „Antwort kaputt“.
|
|
51
|
+
throw new errors_js_1.KasseneckValidationError('listMyPrinters', 'Antwort enthaelt keine Liste (data.printers fehlt)', 'response');
|
|
52
|
+
}
|
|
53
|
+
return liste.map((r) => {
|
|
35
54
|
const d = (r ?? {});
|
|
36
55
|
const e = d.lastResult && typeof d.lastResult === 'object' ? d.lastResult : null;
|
|
37
56
|
return {
|
|
@@ -60,7 +79,7 @@ async function createPrintJob(transport, o) {
|
|
|
60
79
|
if (o.brandMark === true)
|
|
61
80
|
params.brand = true;
|
|
62
81
|
const daten = await transport('createPrintJob', params);
|
|
63
|
-
return { jobId:
|
|
82
|
+
return { jobId: jobKennung('createPrintJob', daten), status: status(daten?.status), result: null };
|
|
64
83
|
}
|
|
65
84
|
/**
|
|
66
85
|
* Stand eines Druckjobs abfragen. Der Aufrufer fragt, bis [isPrintJobFinished]
|
|
@@ -71,7 +90,7 @@ async function getPrintJob(transport, o) {
|
|
|
71
90
|
const d = await transport('getPrintJob', { printerId: o.printerId, jobId: o.jobId });
|
|
72
91
|
const e = d?.result && typeof d.result === 'object' ? d.result : null;
|
|
73
92
|
return {
|
|
74
|
-
jobId:
|
|
93
|
+
jobId: jobKennung('getPrintJob', d), status: status(d?.status),
|
|
75
94
|
createdAt: zahl(d?.createdAt), sentAt: zahl(d?.sentAt),
|
|
76
95
|
result: e ? { success: e.success === true, code: text(e.code), status: text(e.status), at: zahl(e.at) ?? undefined } : null,
|
|
77
96
|
};
|
package/dist/cjs/version.d.ts
CHANGED
package/dist/cjs/version.js
CHANGED
|
@@ -315,10 +315,17 @@ export interface SendReceiptEmailOptions {
|
|
|
315
315
|
}
|
|
316
316
|
/** Was der Versand bestaetigt (Backend: beleg-mail-endpoints.js). */
|
|
317
317
|
export interface SendReceiptEmailResult {
|
|
318
|
-
/**
|
|
318
|
+
/**
|
|
319
|
+
* Adresse in der Form, in der das Backend sie protokolliert hat (getrimmt,
|
|
320
|
+
* klein). Nennt die Antwort keine, die gesendete (getrimmte) Adresse.
|
|
321
|
+
*/
|
|
319
322
|
to: string;
|
|
320
|
-
/**
|
|
321
|
-
|
|
323
|
+
/**
|
|
324
|
+
* Zeitpunkt des Versands, ISO mit Wiener Zonenoffset
|
|
325
|
+
* (`2026-09-11T14:05:00+02:00`). `null`, wenn die Antwort keinen nennt: der
|
|
326
|
+
* Versand ist trotzdem bestaetigt.
|
|
327
|
+
*/
|
|
328
|
+
at: string | null;
|
|
322
329
|
/**
|
|
323
330
|
* Versandweg: `own` (Postfach des Betriebs), `platform` oder
|
|
324
331
|
* `platform_fallback` ([RECEIPT_EMAIL_VIAS]). `null`, wenn die Antwort ihn
|
|
@@ -376,14 +376,17 @@ export async function sendReceiptEmail(transport, options) {
|
|
|
376
376
|
if (options.language !== undefined && options.language !== '')
|
|
377
377
|
params.language = options.language;
|
|
378
378
|
const daten = await transport('sendReceiptEmail', params);
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
379
|
+
// Nachsichtig gelesen (wie der Dart-Zwilling): eine Erfolgsantwort heisst,
|
|
380
|
+
// die Mail ist schon verschickt. Ein Fehler wegen eines fehlenden
|
|
381
|
+
// Antwortfelds luede zum zweiten Versand ein; also zurueck, was da ist.
|
|
382
|
+
const gemeldet = daten?.to;
|
|
383
|
+
const zeit = daten?.at;
|
|
384
|
+
const via = RECEIPT_EMAIL_VIAS.includes(daten?.via) ? daten.via : null;
|
|
385
|
+
return {
|
|
386
|
+
to: typeof gemeldet === 'string' && gemeldet.trim() !== '' ? gemeldet : to,
|
|
387
|
+
at: typeof zeit === 'string' && zeit !== '' ? zeit : null,
|
|
388
|
+
via,
|
|
389
|
+
};
|
|
387
390
|
}
|
|
388
391
|
/**
|
|
389
392
|
* Prueft die Gutschein-Kombination eines Belegs und liefert den ersten
|
|
@@ -45,11 +45,11 @@ export interface Cashregister {
|
|
|
45
45
|
*/
|
|
46
46
|
export interface CashregisterOnboarding {
|
|
47
47
|
cashboxRegistered: boolean;
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
startReceiptCreated: boolean;
|
|
49
|
+
startReceiptTransmitted: boolean;
|
|
50
50
|
cashboxRegisteredAt?: Date;
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
startReceiptCreatedAt?: Date;
|
|
52
|
+
startReceiptTransmittedAt?: Date;
|
|
53
53
|
}
|
|
54
54
|
/** Nutzlast-Form, die dieses Paket liest — die Feldnamen von `listMyCashregisters`. */
|
|
55
55
|
export interface CashregisterPayload {
|
|
@@ -61,13 +61,19 @@ export interface CashregisterPayload {
|
|
|
61
61
|
token?: string | null;
|
|
62
62
|
onboarding?: CashregisterOnboardingPayload | null;
|
|
63
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* `onboarding` am Draht `/v3` (fixtures/v3/antworten/kasse.json): der
|
|
66
|
+
* Startbeleg heisst dort `start_receipt_*`. Die inneren Namen
|
|
67
|
+
* `startbeleg_*` sendet nur `/v1`; wer sie hier laese, meldete jede Kasse
|
|
68
|
+
* als „Startbeleg fehlt“.
|
|
69
|
+
*/
|
|
64
70
|
export interface CashregisterOnboardingPayload {
|
|
65
71
|
cashbox_registered?: boolean | null;
|
|
66
|
-
|
|
67
|
-
|
|
72
|
+
start_receipt_created?: boolean | null;
|
|
73
|
+
start_receipt_transmitted?: boolean | null;
|
|
68
74
|
cashbox_registered_at?: string | null;
|
|
69
|
-
|
|
70
|
-
|
|
75
|
+
start_receipt_created_at?: string | null;
|
|
76
|
+
start_receipt_transmitted_at?: string | null;
|
|
71
77
|
}
|
|
72
78
|
/**
|
|
73
79
|
* Liest eine Kasse aus der Antwort. `id` gewinnt aus der Nutzlast, faellt aber
|
|
@@ -15,11 +15,11 @@ export function fromCashregisterPayload(payload, id) {
|
|
|
15
15
|
...(payload.signature_id ? { signatureId: payload.signature_id } : {}),
|
|
16
16
|
onboarding: {
|
|
17
17
|
cashboxRegistered: ob.cashbox_registered === true,
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
startReceiptCreated: ob.start_receipt_created === true,
|
|
19
|
+
startReceiptTransmitted: ob.start_receipt_transmitted === true,
|
|
20
20
|
...zeitfeld('cashboxRegisteredAt', ob.cashbox_registered_at),
|
|
21
|
-
...zeitfeld('
|
|
22
|
-
...zeitfeld('
|
|
21
|
+
...zeitfeld('startReceiptCreatedAt', ob.start_receipt_created_at),
|
|
22
|
+
...zeitfeld('startReceiptTransmittedAt', ob.start_receipt_transmitted_at),
|
|
23
23
|
},
|
|
24
24
|
};
|
|
25
25
|
}
|
package/dist/esm/pos/client.d.ts
CHANGED
|
@@ -11,7 +11,12 @@ export declare function posSettingsFromWire(data: {
|
|
|
11
11
|
} | null | undefined): PosSettings;
|
|
12
12
|
/** Betriebsweite Einstellungen schreiben (Recht `layout`); liefert den gemischten Stand. */
|
|
13
13
|
export declare function setMyPosSettings(transport: InternerTransport, business: Partial<PosBusinessSettings>): Promise<PosBusinessSettings>;
|
|
14
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Geraete-Einstellungen schreiben (Recht `layout`); liefert den gemischten
|
|
16
|
+
* Stand. `shortcuts` nur als ganze Karte aller bekannten Aktionen
|
|
17
|
+
* ([posSettingsChanges] liefert sie bei jeder Tastenaenderung), sonst wirft
|
|
18
|
+
* der Aufruf vor dem Senden.
|
|
19
|
+
*/
|
|
15
20
|
export declare function setMyRegisterDeviceSettings(transport: InternerTransport, deviceId: string, device: Partial<PosDeviceSettings>): Promise<PosDeviceSettings>;
|
|
16
21
|
/** Eingabe von [setMyPosLogo]: ein Bild als Data-URL (PNG, JPEG, SVG) oder das Entfernen. */
|
|
17
22
|
export type SetMyPosLogoOptions = {
|
package/dist/esm/pos/client.js
CHANGED
|
@@ -50,7 +50,12 @@ export async function setMyPosSettings(transport, business) {
|
|
|
50
50
|
const daten = await transport(name, { business });
|
|
51
51
|
return mergePosSettings(POS_BUSINESS_DEFAULTS, objekt(daten?.business));
|
|
52
52
|
}
|
|
53
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* Geraete-Einstellungen schreiben (Recht `layout`); liefert den gemischten
|
|
55
|
+
* Stand. `shortcuts` nur als ganze Karte aller bekannten Aktionen
|
|
56
|
+
* ([posSettingsChanges] liefert sie bei jeder Tastenaenderung), sonst wirft
|
|
57
|
+
* der Aufruf vor dem Senden.
|
|
58
|
+
*/
|
|
54
59
|
export async function setMyRegisterDeviceSettings(transport, deviceId, device) {
|
|
55
60
|
const name = 'setMyRegisterDeviceSettings';
|
|
56
61
|
if (typeof deviceId !== 'string' || deviceId.trim() === '') {
|
|
@@ -70,8 +75,15 @@ export async function setMyRegisterDeviceSettings(transport, deviceId, device) {
|
|
|
70
75
|
throw new KasseneckValidationError(name, `device.shortcuts.${aktion}: unbekannte Aktion`, 'request');
|
|
71
76
|
}
|
|
72
77
|
}
|
|
73
|
-
//
|
|
74
|
-
//
|
|
78
|
+
// Nur die ganze Karte: der Server prueft Doppelbelegungen nur in der
|
|
79
|
+
// gesendeten Karte, eine halbe (`{cash: ['Mod+K']}`) liesse eine
|
|
80
|
+
// Doppelbelegung mit einer gespeicherten Taste durch. posSettingsChanges
|
|
81
|
+
// liefert bei jeder Tastenaenderung die ganze Karte.
|
|
82
|
+
const fehlt = POS_SHORTCUT_ACTIONS.filter((a) => karte[a] === undefined);
|
|
83
|
+
if (fehlt.length > 0) {
|
|
84
|
+
throw new KasseneckValidationError(name, `device.shortcuts: ganze Karte senden (posSettingsChanges), es fehlen ${fehlt.join(', ')}`, 'request');
|
|
85
|
+
}
|
|
86
|
+
// Doppelbelegung in der ganzen Karte, also in der ganzen Belegung.
|
|
75
87
|
const konflikt = posShortcutConflict(karte);
|
|
76
88
|
if (konflikt) {
|
|
77
89
|
throw new KasseneckValidationError(name, `device.shortcuts.${konflikt.action}: Taste ${konflikt.key} schon belegt (${konflikt.heldBy})`, 'request');
|
package/dist/esm/pos/drucker.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { KasseneckValidationError } from '../client/errors.js';
|
|
1
2
|
import { rasterRowsBase64 } from '../printing/index.js';
|
|
2
3
|
/** Stand eines Druckjobs (Katalog `DRUCKJOB`). */
|
|
3
4
|
export const PRINT_JOB_STATUSES = ['pending', 'sent', 'printed', 'failed', 'expired'];
|
|
@@ -22,9 +23,27 @@ const STATUS = new Set(PRINT_JOB_STATUSES);
|
|
|
22
23
|
function status(v) {
|
|
23
24
|
return typeof v === 'string' && STATUS.has(v) ? v : 'unknown';
|
|
24
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Die Kennung eines Jobs aus der Antwort. Ohne sie kann niemand den Job
|
|
28
|
+
* abfragen; ein leerer Text waere ein angeblich angelegter Job, und der
|
|
29
|
+
* Kassier druckte ein zweites Mal.
|
|
30
|
+
*/
|
|
31
|
+
function jobKennung(name, d) {
|
|
32
|
+
const id = d?.jobId;
|
|
33
|
+
if (typeof id !== 'string' || id === '') {
|
|
34
|
+
throw new KasseneckValidationError(name, 'Antwort enthaelt keine Kennung (data.jobId fehlt)', 'response');
|
|
35
|
+
}
|
|
36
|
+
return id;
|
|
37
|
+
}
|
|
25
38
|
export async function listMyPrinters(transport) {
|
|
26
39
|
const daten = await transport('listMyPrinters', {});
|
|
27
|
-
|
|
40
|
+
const liste = daten?.printers;
|
|
41
|
+
if (!Array.isArray(liste)) {
|
|
42
|
+
// Keine Liste ist etwas anderes als eine leere Liste: „noch kein Drucker“
|
|
43
|
+
// darf nicht aussehen wie „Antwort kaputt“.
|
|
44
|
+
throw new KasseneckValidationError('listMyPrinters', 'Antwort enthaelt keine Liste (data.printers fehlt)', 'response');
|
|
45
|
+
}
|
|
46
|
+
return liste.map((r) => {
|
|
28
47
|
const d = (r ?? {});
|
|
29
48
|
const e = d.lastResult && typeof d.lastResult === 'object' ? d.lastResult : null;
|
|
30
49
|
return {
|
|
@@ -53,7 +72,7 @@ export async function createPrintJob(transport, o) {
|
|
|
53
72
|
if (o.brandMark === true)
|
|
54
73
|
params.brand = true;
|
|
55
74
|
const daten = await transport('createPrintJob', params);
|
|
56
|
-
return { jobId:
|
|
75
|
+
return { jobId: jobKennung('createPrintJob', daten), status: status(daten?.status), result: null };
|
|
57
76
|
}
|
|
58
77
|
/**
|
|
59
78
|
* Stand eines Druckjobs abfragen. Der Aufrufer fragt, bis [isPrintJobFinished]
|
|
@@ -64,7 +83,7 @@ export async function getPrintJob(transport, o) {
|
|
|
64
83
|
const d = await transport('getPrintJob', { printerId: o.printerId, jobId: o.jobId });
|
|
65
84
|
const e = d?.result && typeof d.result === 'object' ? d.result : null;
|
|
66
85
|
return {
|
|
67
|
-
jobId:
|
|
86
|
+
jobId: jobKennung('getPrintJob', d), status: status(d?.status),
|
|
68
87
|
createdAt: zahl(d?.createdAt), sentAt: zahl(d?.sentAt),
|
|
69
88
|
result: e ? { success: e.success === true, code: text(e.code), status: text(e.status), at: zahl(e.at) ?? undefined } : null,
|
|
70
89
|
};
|
package/dist/esm/version.d.ts
CHANGED
package/dist/esm/version.js
CHANGED
package/fixtures/pos-texts.json
CHANGED
package/fixtures/surface.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kreiseck/kasseneck-api",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.3",
|
|
4
4
|
"description": "Austrian fiscal cash register (RKSV) client for JavaScript and TypeScript: signed receipts, cancellations, card payments, receipt printing (ESC/POS), invoices. RKSV-Registrierkasse für JavaScript und TypeScript.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Kreiseck",
|