@kreiseck/kasseneck-api 1.10.0 → 1.11.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 +245 -0
- package/dist/cjs/client/aufrufe.d.ts +5 -5
- package/dist/cjs/client/aufrufe.js +22 -2
- package/dist/cjs/client/errors.js +2 -0
- package/dist/cjs/client/receipts.d.ts +34 -1
- package/dist/cjs/client/receipts.js +34 -1
- package/dist/cjs/client/reports.d.ts +4 -4
- package/dist/cjs/client/reports.js +4 -4
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +9 -2
- package/dist/cjs/inventory/vertrag.d.ts +1 -1
- package/dist/cjs/inventory/vertrag.js +2 -0
- package/dist/cjs/invoice/vertrag.d.ts +1 -1
- package/dist/cjs/invoice/vertrag.js +2 -0
- package/dist/cjs/models/cancellation.d.ts +49 -1
- package/dist/cjs/models/cancellation.js +139 -1
- package/dist/cjs/models/index.d.ts +1 -1
- package/dist/cjs/models/index.js +9 -2
- package/dist/cjs/models/payment-errors.d.ts +1 -1
- package/dist/cjs/models/payment-errors.js +2 -0
- package/dist/cjs/models/receipt-email.d.ts +1 -1
- package/dist/cjs/models/receipt-email.js +2 -0
- package/dist/cjs/models/receipt-errors.d.ts +1 -1
- package/dist/cjs/models/receipt-errors.js +2 -0
- package/dist/cjs/models/receipt-item.d.ts +10 -0
- package/dist/cjs/models/receipt-item.js +3 -0
- package/dist/cjs/pos/client.js +10 -0
- package/dist/cjs/pos/errors.d.ts +4 -3
- package/dist/cjs/pos/errors.js +21 -2
- package/dist/cjs/pos/index.d.ts +6 -2
- package/dist/cjs/pos/index.js +33 -3
- package/dist/cjs/pos/schicht-lesen.d.ts +39 -0
- package/dist/cjs/pos/schicht-lesen.js +405 -0
- package/dist/cjs/pos/schicht-typen.d.ts +380 -0
- package/dist/cjs/pos/schicht-typen.js +59 -0
- package/dist/cjs/pos/schicht.d.ts +208 -0
- package/dist/cjs/pos/schicht.js +235 -0
- package/dist/cjs/pos/settings.d.ts +37 -1
- package/dist/cjs/pos/settings.js +43 -3
- package/dist/cjs/pos/texte.d.ts +627 -0
- package/dist/cjs/pos/texte.js +236 -0
- package/dist/cjs/react/index.js +1 -1
- package/dist/cjs/receipt/grid.js +2 -2
- package/dist/cjs/receipt/layout.d.ts +5 -0
- package/dist/cjs/receipt/shift-sheet.d.ts +33 -0
- package/dist/cjs/receipt/shift-sheet.js +207 -0
- package/dist/cjs/register/errors.d.ts +1 -1
- package/dist/cjs/register/errors.js +2 -0
- package/dist/cjs/stored/draht.d.ts +1 -1
- package/dist/cjs/stored/draht.js +4 -3
- package/dist/cjs/stored/einstellungen.js +26 -3
- package/dist/cjs/stored/vokabular.d.ts +1 -1
- package/dist/cjs/stored/vokabular.js +118 -12
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/client/aufrufe.d.ts +5 -5
- package/dist/esm/client/aufrufe.js +22 -2
- package/dist/esm/client/errors.js +2 -0
- package/dist/esm/client/receipts.d.ts +34 -1
- package/dist/esm/client/receipts.js +35 -2
- package/dist/esm/client/reports.d.ts +4 -4
- package/dist/esm/client/reports.js +4 -4
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/inventory/vertrag.d.ts +1 -1
- package/dist/esm/inventory/vertrag.js +2 -0
- package/dist/esm/invoice/vertrag.d.ts +1 -1
- package/dist/esm/invoice/vertrag.js +2 -0
- package/dist/esm/models/cancellation.d.ts +49 -1
- package/dist/esm/models/cancellation.js +132 -0
- package/dist/esm/models/index.d.ts +1 -1
- package/dist/esm/models/index.js +1 -1
- package/dist/esm/models/payment-errors.d.ts +1 -1
- package/dist/esm/models/payment-errors.js +2 -0
- package/dist/esm/models/receipt-email.d.ts +1 -1
- package/dist/esm/models/receipt-email.js +2 -0
- package/dist/esm/models/receipt-errors.d.ts +1 -1
- package/dist/esm/models/receipt-errors.js +2 -0
- package/dist/esm/models/receipt-item.d.ts +10 -0
- package/dist/esm/models/receipt-item.js +3 -0
- package/dist/esm/pos/client.js +11 -1
- package/dist/esm/pos/errors.d.ts +4 -3
- package/dist/esm/pos/errors.js +21 -2
- package/dist/esm/pos/index.d.ts +6 -2
- package/dist/esm/pos/index.js +7 -2
- package/dist/esm/pos/schicht-lesen.d.ts +39 -0
- package/dist/esm/pos/schicht-lesen.js +392 -0
- package/dist/esm/pos/schicht-typen.d.ts +380 -0
- package/dist/esm/pos/schicht-typen.js +56 -0
- package/dist/esm/pos/schicht.d.ts +208 -0
- package/dist/esm/pos/schicht.js +222 -0
- package/dist/esm/pos/settings.d.ts +37 -1
- package/dist/esm/pos/settings.js +40 -2
- package/dist/esm/pos/texte.d.ts +627 -0
- package/dist/esm/pos/texte.js +236 -0
- package/dist/esm/react/index.js +1 -1
- package/dist/esm/receipt/grid.js +2 -2
- package/dist/esm/receipt/layout.d.ts +5 -0
- package/dist/esm/receipt/shift-sheet.d.ts +33 -0
- package/dist/esm/receipt/shift-sheet.js +203 -0
- package/dist/esm/register/errors.d.ts +1 -1
- package/dist/esm/register/errors.js +2 -0
- package/dist/esm/stored/draht.d.ts +1 -1
- package/dist/esm/stored/draht.js +4 -3
- package/dist/esm/stored/einstellungen.js +27 -4
- package/dist/esm/stored/vokabular.d.ts +1 -1
- package/dist/esm/stored/vokabular.js +118 -12
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/fixtures/cancellation-tip-cases.json +679 -0
- package/fixtures/expected/cash-movement.grid32.txt +15 -0
- package/fixtures/expected/cash-movement.grid48.txt +15 -0
- package/fixtures/expected/cash-movement.lines.json +171 -0
- package/fixtures/expected/shift-close-blind.grid32.txt +28 -0
- package/fixtures/expected/shift-close-blind.grid48.txt +27 -0
- package/fixtures/expected/shift-close-blind.lines.json +275 -0
- package/fixtures/expected/shift-close-put-in.grid32.txt +38 -0
- package/fixtures/expected/shift-close-put-in.grid48.txt +35 -0
- package/fixtures/expected/shift-close-put-in.lines.json +403 -0
- package/fixtures/expected/shift-close-take-out.grid32.txt +38 -0
- package/fixtures/expected/shift-close-take-out.grid48.txt +35 -0
- package/fixtures/expected/shift-close-take-out.lines.json +403 -0
- package/fixtures/expected/shift-close.grid32.txt +37 -0
- package/fixtures/expected/shift-close.grid48.txt +35 -0
- package/fixtures/expected/shift-close.lines.json +413 -0
- package/fixtures/expected/shift-interim.grid32.txt +28 -0
- package/fixtures/expected/shift-interim.grid48.txt +27 -0
- package/fixtures/expected/shift-interim.lines.json +293 -0
- 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-message-cases.json +45 -0
- package/fixtures/pos-texts.json +723 -1
- package/fixtures/receipt-due-generated.json +1 -1
- package/fixtures/shift-cases.json +87 -0
- package/fixtures/shift-receipts.json +41 -0
- package/fixtures/surface.json +119 -3
- package/fixtures/v3/antworten/belege.json +1 -1
- package/fixtures/v3/antworten/belegmail.json +1 -1
- package/fixtures/v3/antworten/kasse-belege.json +1 -1
- package/fixtures/v3/antworten/kasse.json +10874 -4865
- package/fixtures/v3/antworten/lager.json +1 -1
- package/fixtures/v3/antworten/rechnungen.json +1 -1
- package/fixtures/v3/antworten/storno.json +1 -1
- package/fixtures/v3/stored/belege.json +18 -6
- package/fixtures/v3/stored/kasse.json +4667 -183
- package/fixtures/v3/stored/rechnungen.json +1 -1
- package/fixtures/v3/v3-vokabular.json +739 -32
- package/fixtures/v3/zahlbetrag-faelle.json +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getMyDrawerState = getMyDrawerState;
|
|
4
|
+
exports.openMyShift = openMyShift;
|
|
5
|
+
exports.recordMyCashMovement = recordMyCashMovement;
|
|
6
|
+
exports.logMyDrawerOpenings = logMyDrawerOpenings;
|
|
7
|
+
exports.getMyShiftReport = getMyShiftReport;
|
|
8
|
+
exports.closeMyShift = closeMyShift;
|
|
9
|
+
exports.sumDenominations = sumDenominations;
|
|
10
|
+
exports.parseCentsAllowZero = parseCentsAllowZero;
|
|
11
|
+
exports.newIdempotencyKey = newIdempotencyKey;
|
|
12
|
+
exports.shiftTipLines = shiftTipLines;
|
|
13
|
+
exports.durationText = durationText;
|
|
14
|
+
const errors_js_1 = require("../client/errors.js");
|
|
15
|
+
const schreiben_js_1 = require("../inventory/schreiben.js");
|
|
16
|
+
const schicht_lesen_js_1 = require("./schicht-lesen.js");
|
|
17
|
+
const texte_js_1 = require("./texte.js");
|
|
18
|
+
const schicht_typen_js_1 = require("./schicht-typen.js");
|
|
19
|
+
const antwort = (name) => ({ name, pfad: '', scope: 'response' });
|
|
20
|
+
function anfragefehler(name, grund) {
|
|
21
|
+
return new errors_js_1.KasseneckValidationError(name, grund, 'request');
|
|
22
|
+
}
|
|
23
|
+
/** Eine Kennung, die gesendet werden muss. */
|
|
24
|
+
function kennung(name, p, feld) {
|
|
25
|
+
const w = p[feld];
|
|
26
|
+
if (typeof w !== 'string' || w.trim() === '')
|
|
27
|
+
throw anfragefehler(name, `${feld} fehlt`);
|
|
28
|
+
}
|
|
29
|
+
/** Ein Betrag in Cent: ganze Zahl, sonst wirft der Aufruf vor dem Senden. */
|
|
30
|
+
function cent(name, feld, w) {
|
|
31
|
+
if (typeof w !== 'number' || !Number.isSafeInteger(w))
|
|
32
|
+
throw anfragefehler(name, `${feld} muss eine ganze Zahl (Cent) sein`);
|
|
33
|
+
}
|
|
34
|
+
function stueckelungPruefen(name, p) {
|
|
35
|
+
const w = p.denominations;
|
|
36
|
+
if (w === undefined || w === null)
|
|
37
|
+
return;
|
|
38
|
+
if (typeof w !== 'object' || Array.isArray(w))
|
|
39
|
+
throw anfragefehler(name, 'denominations muss eine Karte Wert -> Anzahl sein');
|
|
40
|
+
for (const [k, anzahl] of Object.entries(w))
|
|
41
|
+
cent(name, `denominations.${k}`, anzahl);
|
|
42
|
+
}
|
|
43
|
+
async function rufe(transport, name, p, lese) {
|
|
44
|
+
return lese(antwort(name), await transport(name, p));
|
|
45
|
+
}
|
|
46
|
+
/** Stand der Lade: Rechte, offene Schicht, Trinkgeld-Ansprueche und (mit `cashView`) Soll und letzte Oeffnungen. */
|
|
47
|
+
async function getMyDrawerState(transport, options = {}) {
|
|
48
|
+
const name = 'getMyDrawerState';
|
|
49
|
+
const p = (0, schreiben_js_1.anfrage)(name, options);
|
|
50
|
+
if (p.drawerId === '')
|
|
51
|
+
delete p.drawerId;
|
|
52
|
+
return rufe(transport, name, p, schicht_lesen_js_1.ladeStand);
|
|
53
|
+
}
|
|
54
|
+
/** Schicht oeffnen: gezaehltes Startgeld oder den Bestand uebernehmen (Recht `shift`). */
|
|
55
|
+
async function openMyShift(transport, options) {
|
|
56
|
+
const name = 'openMyShift';
|
|
57
|
+
const p = (0, schreiben_js_1.anfrage)(name, options);
|
|
58
|
+
kennung(name, p, 'drawerId');
|
|
59
|
+
(0, schreiben_js_1.schluessel)(name, p, { pflicht: true });
|
|
60
|
+
if (p.openingFloatCents !== undefined)
|
|
61
|
+
cent(name, 'openingFloatCents', p.openingFloatCents);
|
|
62
|
+
stueckelungPruefen(name, p);
|
|
63
|
+
return rufe(transport, name, p, schicht_lesen_js_1.geoeffnet);
|
|
64
|
+
}
|
|
65
|
+
/** Ein- oder Auszahlung buchen (Recht `cashMove`); Antwort mit den Bon-Daten „Kassenbewegung“. */
|
|
66
|
+
async function recordMyCashMovement(transport, options) {
|
|
67
|
+
const name = 'recordMyCashMovement';
|
|
68
|
+
const p = (0, schreiben_js_1.anfrage)(name, options);
|
|
69
|
+
kennung(name, p, 'drawerId');
|
|
70
|
+
(0, schreiben_js_1.schluessel)(name, p, { pflicht: true });
|
|
71
|
+
cent(name, 'amountCents', p.amountCents);
|
|
72
|
+
// Nur pruefen, wenn gesetzt: Bank/Tresor fragt die Kasse nicht mehr ab.
|
|
73
|
+
if (p.location !== undefined && !schicht_typen_js_1.CASH_LOCATIONS.includes(p.location)) {
|
|
74
|
+
throw anfragefehler(name, `location muss ${schicht_typen_js_1.CASH_LOCATIONS.join(' oder ')} sein`);
|
|
75
|
+
}
|
|
76
|
+
return rufe(transport, name, p, schicht_lesen_js_1.gebucht);
|
|
77
|
+
}
|
|
78
|
+
/** Oeffnungen der Lade melden (auch nachgesendet); doppelt gemeldete zaehlen einmal. */
|
|
79
|
+
async function logMyDrawerOpenings(transport, options) {
|
|
80
|
+
const name = 'logMyDrawerOpenings';
|
|
81
|
+
const p = (0, schreiben_js_1.anfrage)(name, options);
|
|
82
|
+
kennung(name, p, 'drawerId');
|
|
83
|
+
const eintraege = p.entries;
|
|
84
|
+
if (!Array.isArray(eintraege) || eintraege.length === 0)
|
|
85
|
+
throw anfragefehler(name, 'entries muss 1–50 Eintraege haben');
|
|
86
|
+
eintraege.forEach((e, i) => {
|
|
87
|
+
const k = e !== null && typeof e === 'object' ? e.idempotencyKey : undefined;
|
|
88
|
+
if (typeof k !== 'string' || k.trim() === '')
|
|
89
|
+
throw anfragefehler(name, `entries[${i}].idempotencyKey fehlt`);
|
|
90
|
+
});
|
|
91
|
+
return rufe(transport, name, p, schicht_lesen_js_1.gemeldet);
|
|
92
|
+
}
|
|
93
|
+
/** Bericht der Schicht: Schicht, Bewegungen und Bon-Daten (X-Bon, bei geschlossener Schicht der Z-Bon). */
|
|
94
|
+
async function getMyShiftReport(transport, options) {
|
|
95
|
+
const name = 'getMyShiftReport';
|
|
96
|
+
const p = (0, schreiben_js_1.anfrage)(name, options);
|
|
97
|
+
kennung(name, p, 'shiftId');
|
|
98
|
+
return rufe(transport, name, p, schicht_lesen_js_1.bericht);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Schicht schliessen (Recht `shift`). `status: 'recount'` heisst: bitte noch
|
|
102
|
+
* einmal zaehlen und erneut senden (kein Fehler); nach dem zweiten Zaehlen
|
|
103
|
+
* schliesst der Server, bei grosser Abweichung nur mit `comment`. Mit
|
|
104
|
+
* `checkOnly` nur pruefen: `status: 'ready'` statt Schliessen.
|
|
105
|
+
*/
|
|
106
|
+
async function closeMyShift(transport, options) {
|
|
107
|
+
const name = 'closeMyShift';
|
|
108
|
+
const p = (0, schreiben_js_1.anfrage)(name, options);
|
|
109
|
+
kennung(name, p, 'shiftId');
|
|
110
|
+
(0, schreiben_js_1.schluessel)(name, p, { pflicht: true });
|
|
111
|
+
cent(name, 'countedCents', p.countedCents);
|
|
112
|
+
stueckelungPruefen(name, p);
|
|
113
|
+
if (p.tipPayouts !== undefined && p.tipPayouts !== null) {
|
|
114
|
+
if (!Array.isArray(p.tipPayouts))
|
|
115
|
+
throw anfragefehler(name, 'tipPayouts muss eine Liste sein');
|
|
116
|
+
p.tipPayouts.forEach((a, i) => cent(name, `tipPayouts[${i}].cents`, a !== null && typeof a === 'object' ? a.cents : undefined));
|
|
117
|
+
}
|
|
118
|
+
if (p.checkOnly !== undefined && typeof p.checkOnly !== 'boolean')
|
|
119
|
+
throw anfragefehler(name, 'checkOnly muss true oder false sein');
|
|
120
|
+
// Nur die Form: die Art (Katalog) und die Grenzen prueft der Server.
|
|
121
|
+
if (p.afterCount !== undefined && p.afterCount !== null) {
|
|
122
|
+
if (typeof p.afterCount !== 'object' || Array.isArray(p.afterCount))
|
|
123
|
+
throw anfragefehler(name, 'afterCount muss ein Objekt { type, amountCents } sein');
|
|
124
|
+
cent(name, 'afterCount.amountCents', p.afterCount.amountCents);
|
|
125
|
+
}
|
|
126
|
+
return rufe(transport, name, p, schicht_lesen_js_1.abschluss);
|
|
127
|
+
}
|
|
128
|
+
// ---- Helfer der Kasse ---------------------------------------------------------
|
|
129
|
+
const ANZAHL_MAX = 100000;
|
|
130
|
+
const WERTE = new Set(schicht_typen_js_1.EUR_DENOMINATIONS.map(String));
|
|
131
|
+
/**
|
|
132
|
+
* Summe einer Stueckelung in Cent, oder `null`, wenn sie keine ist: ein
|
|
133
|
+
* Schluessel, der kein Euro-Wert ist ([EUR_DENOMINATIONS], genau so
|
|
134
|
+
* geschrieben, `"500"`, nicht `"0500"`), eine Anzahl, die keine ganze Zahl
|
|
135
|
+
* von 0 bis 100 000 ist. Dieselbe Regel wie am Server
|
|
136
|
+
* (`invalid_denominations`). Gemeinsame Faelle mit dem Dart-Zwilling:
|
|
137
|
+
* `fixtures/shift-cases.json`.
|
|
138
|
+
*/
|
|
139
|
+
function sumDenominations(denominations) {
|
|
140
|
+
if (denominations === null || typeof denominations !== 'object' || Array.isArray(denominations))
|
|
141
|
+
return null;
|
|
142
|
+
let summe = 0;
|
|
143
|
+
for (const [wert, anzahl] of Object.entries(denominations)) {
|
|
144
|
+
if (!WERTE.has(wert))
|
|
145
|
+
return null;
|
|
146
|
+
if (typeof anzahl !== 'number' || !Number.isSafeInteger(anzahl) || anzahl < 0 || anzahl > ANZAHL_MAX)
|
|
147
|
+
return null;
|
|
148
|
+
summe += Number(wert) * anzahl;
|
|
149
|
+
}
|
|
150
|
+
return summe;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Ein eingetippter Betrag in Cent, **ohne Gleitkomma**: `'12,5'` → `1250`,
|
|
154
|
+
* `'0'` → `0` (anders als beim Kassieren ist 0 hier gueltig: eine leere Lade,
|
|
155
|
+
* kein Startgeld). Dezimaltrenner Komma oder Punkt mit einer oder zwei
|
|
156
|
+
* Nachkommastellen; `null` fuer leer, Vorzeichen, Tausendertrenner
|
|
157
|
+
* (`'1.000'`, `'1 000'`), drei Nachkommastellen, Euro-Zeichen und alles
|
|
158
|
+
* ueber einer sicheren Ganzzahl. Gemeinsame Faelle mit dem Dart-Zwilling:
|
|
159
|
+
* `fixtures/shift-cases.json`.
|
|
160
|
+
*/
|
|
161
|
+
function parseCentsAllowZero(text) {
|
|
162
|
+
if (typeof text !== 'string')
|
|
163
|
+
return null;
|
|
164
|
+
const m = /^(\d+)(?:[.,](\d{1,2}))?$/.exec(text.trim());
|
|
165
|
+
if (!m)
|
|
166
|
+
return null;
|
|
167
|
+
const cents = BigInt(m[1]) * 100n + BigInt((m[2] ?? '').padEnd(2, '0'));
|
|
168
|
+
return cents <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(cents) : null;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Ein frischer Idempotenzschluessel fuer einen neuen Vorgang: `kasse-` und
|
|
172
|
+
* 32 Hex-Zeichen aus dem sicheren Zufall (`crypto.getRandomValues`), dieselbe
|
|
173
|
+
* Form wie beim Zaehlen der Inventur in der Kassen-App. Fuer „Erneut senden“
|
|
174
|
+
* nie einen neuen ziehen, sondern den alten behalten.
|
|
175
|
+
*/
|
|
176
|
+
function newIdempotencyKey() {
|
|
177
|
+
const zufall = globalThis.crypto;
|
|
178
|
+
if (!zufall || typeof zufall.getRandomValues !== 'function') {
|
|
179
|
+
throw new errors_js_1.KasseneckValidationError('newIdempotencyKey', 'kein sicherer Zufall vorhanden (crypto.getRandomValues)', 'request');
|
|
180
|
+
}
|
|
181
|
+
const bytes = zufall.getRandomValues(new Uint8Array(16));
|
|
182
|
+
return `kasse-${Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('')}`;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Was vom Trinkgeld eines Mitarbeiters dasteht – auf dem Bon, im Kassenstand
|
|
186
|
+
* und beim Abschluss gleich (Rulings R50/R51): „verdient“ (sofort + über
|
|
187
|
+
* Lohn) immer, „über Lohn“, „schon genommen“, „selbst zurückgegeben“ (R62)
|
|
188
|
+
* und „offen“ nur, wenn nicht 0. Davor „aus früheren Schichten“ (R64, nur ≠ 0):
|
|
189
|
+
* offen = aus früheren Schichten + verdient − über Lohn − schon genommen +
|
|
190
|
+
* selbst zurückgegeben.
|
|
191
|
+
* Ist alles 0, gibt es keine Zeile, und der Mitarbeiter entfaellt ganz. Ohne
|
|
192
|
+
* `openCents` (Laufstand) zaehlt offen als 0. Gemeinsame Faelle mit dem
|
|
193
|
+
* Dart-Zwilling: `fixtures/shift-cases.json`.
|
|
194
|
+
*/
|
|
195
|
+
function shiftTipLines(tip) {
|
|
196
|
+
const verdient = tip.receivedImmediatelyCents + tip.retainedCents;
|
|
197
|
+
const vortrag = tip.carriedOverCents ?? 0;
|
|
198
|
+
const zeilen = [
|
|
199
|
+
['shift_receipt.tip_retained', tip.retainedCents],
|
|
200
|
+
['shift_receipt.tip_paid_out', tip.paidOutCents],
|
|
201
|
+
['shift_receipt.tip_refunded_by_employee', tip.refundedByEmployeeCents ?? 0],
|
|
202
|
+
['shift_receipt.tip_open', tip.openCents ?? 0],
|
|
203
|
+
];
|
|
204
|
+
const rest = zeilen.filter(([, cents]) => cents !== 0);
|
|
205
|
+
if (verdient === 0 && rest.length === 0 && vortrag === 0)
|
|
206
|
+
return [];
|
|
207
|
+
const davor = vortrag !== 0 ? [['shift_receipt.tip_carried_over', vortrag]] : [];
|
|
208
|
+
return [...davor, ['shift_receipt.tip_earned', verdient], ...rest].map(([key, cents]) => ({ key, text: (0, texte_js_1.labelText)(key), cents }));
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Dauer für Menschen aus ganzen Minuten: unter 1 Std. „45 Min.“, unter 1 Tag
|
|
212
|
+
* „8 Std. 32 Min.“ (bei 0 Minuten nur „8 Std.“), ab 1 Tag „1 Tag 3 Std.“ bzw.
|
|
213
|
+
* „2 Tage“ (bei 0 Stunden ohne Stunden). Negatives und Unsinn zählt als 0;
|
|
214
|
+
* Bruchteile werden abgeschnitten. Gemeinsame Fälle mit dem Dart-Zwilling:
|
|
215
|
+
* `fixtures/shift-cases.json` (`durationText`).
|
|
216
|
+
*/
|
|
217
|
+
function durationText(minutes) {
|
|
218
|
+
const gesamt = Number.isFinite(minutes) && minutes > 0 ? Math.floor(minutes) : 0;
|
|
219
|
+
const tage = Math.floor(gesamt / 1440);
|
|
220
|
+
const stunden = Math.floor((gesamt % 1440) / 60);
|
|
221
|
+
const rest = gesamt % 60;
|
|
222
|
+
const teile = [];
|
|
223
|
+
if (tage > 0) {
|
|
224
|
+
teile.push((0, texte_js_1.labelText)(tage === 1 ? 'duration.days_one' : 'duration.days_other', { days: tage }));
|
|
225
|
+
if (stunden > 0)
|
|
226
|
+
teile.push((0, texte_js_1.labelText)('duration.hours', { hours: stunden }));
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
if (stunden > 0)
|
|
230
|
+
teile.push((0, texte_js_1.labelText)('duration.hours', { hours: stunden }));
|
|
231
|
+
if (rest > 0 || stunden === 0)
|
|
232
|
+
teile.push((0, texte_js_1.labelText)('duration.minutes', { minutes: rest }));
|
|
233
|
+
}
|
|
234
|
+
return teile.join(' ');
|
|
235
|
+
}
|
|
@@ -189,6 +189,13 @@ export interface PosBusinessSettings {
|
|
|
189
189
|
glass: boolean;
|
|
190
190
|
/** Hilfetexte in den Chef-Einstellungen anzeigen. */
|
|
191
191
|
hints: boolean;
|
|
192
|
+
/**
|
|
193
|
+
* Bar-Trinkgeld behaelt der Mitarbeiter gleich: Vorbelegung des Schalters
|
|
194
|
+
* „gleich behalten“ beim Kassieren (je Verkauf aenderbar). Optional: der
|
|
195
|
+
* Server sendet das Feld nur, wenn es gespeichert ist; fehlt es, gilt aus.
|
|
196
|
+
* Lesen ueber [posTipKeptByDefault]. Siehe [POS_BUSINESS_OPTIONAL_FIELDS].
|
|
197
|
+
*/
|
|
198
|
+
tipKeptByDefault?: boolean;
|
|
192
199
|
}
|
|
193
200
|
/** Aktionen der Kasse, die eine Taste bekommen koennen (Schluessel von `device.shortcuts`). */
|
|
194
201
|
export declare const POS_SHORTCUT_ACTIONS: readonly ["checkout", "complete", "cancel", "customAmount", "cash", "card", "exactAmount", "receipts", "undoLast", "settings", "logout", "tip", "fullscreen", "clearTendered", "clearCart", "splitPayment"];
|
|
@@ -241,6 +248,13 @@ export interface PosDeviceSettings {
|
|
|
241
248
|
qrMode: PosOpen<PosQrMode>;
|
|
242
249
|
drawerEnabled: boolean;
|
|
243
250
|
drawerAutoOpen: PosOpen<PosDrawerAutoOpen>;
|
|
251
|
+
/**
|
|
252
|
+
* Lade dieses Geraets (Schichtbetrieb). Optional: der Server sendet das
|
|
253
|
+
* Feld nur, wenn eine Lade zugeordnet ist; fehlt es, gilt die Hauptlade der
|
|
254
|
+
* Kasse. Beim Schreiben entfernt `null` die Zuordnung. Siehe
|
|
255
|
+
* [POS_DEVICE_OPTIONAL_FIELDS].
|
|
256
|
+
*/
|
|
257
|
+
drawerId?: string | null;
|
|
244
258
|
terminalIp: string;
|
|
245
259
|
terminalPort: number;
|
|
246
260
|
terminalVia: PosOpen<PosTerminalVia>;
|
|
@@ -257,6 +271,25 @@ export interface PosSettings {
|
|
|
257
271
|
}
|
|
258
272
|
export declare const POS_BUSINESS_DEFAULTS: Readonly<PosBusinessSettings>;
|
|
259
273
|
export declare const POS_DEVICE_DEFAULTS: Readonly<PosDeviceSettings>;
|
|
274
|
+
/**
|
|
275
|
+
* Optionale Geraete-Einstellungen: ohne Standardwert, der Server sendet sie
|
|
276
|
+
* nur, wenn sie gesetzt sind (Backend `GERAET_OPTIONAL`). Sie fehlen darum in
|
|
277
|
+
* [POS_DEVICE_DEFAULTS]; [mergePosSettings] uebernimmt sie, wenn sie als
|
|
278
|
+
* Kennung kommen, und der Schreibweg nimmt sie als Kennung oder `null`
|
|
279
|
+
* (Zuordnung entfernen).
|
|
280
|
+
*/
|
|
281
|
+
export declare const POS_DEVICE_OPTIONAL_FIELDS: readonly ["drawerId"];
|
|
282
|
+
/** Gilt dieser Wert fuer ein optionales Feld? Lesen: nur eine Kennung; Schreiben: auch `null`. */
|
|
283
|
+
export declare function _optionalerWert(wert: unknown, schreiben: boolean): boolean;
|
|
284
|
+
/**
|
|
285
|
+
* Optionale Betriebs-Einstellungen (Schalter): ohne Standardwert, der Server
|
|
286
|
+
* sendet sie nur, wenn sie gespeichert sind (Backend `BETRIEB_OPTIONAL`).
|
|
287
|
+
* [mergePosSettings] uebernimmt sie nur als Wahrheitswert; der Schreibweg
|
|
288
|
+
* nimmt nur `true`/`false`.
|
|
289
|
+
*/
|
|
290
|
+
export declare const POS_BUSINESS_OPTIONAL_FIELDS: readonly ["tipKeptByDefault"];
|
|
291
|
+
/** Bar-Trinkgeld „gleich behalten“ vorbelegt? Fehlt die Einstellung, gilt aus. */
|
|
292
|
+
export declare function posTipKeptByDefault(business: Readonly<Partial<PosBusinessSettings>> | null | undefined): boolean;
|
|
260
293
|
/**
|
|
261
294
|
* Die Wertemenge je Feld, soweit das Feld eine hat: dagegen prueft der
|
|
262
295
|
* Schreibweg vor dem Senden (ein deutscher Wert wie `'nacht'` geht so gar
|
|
@@ -275,7 +308,10 @@ export declare const _ALTFORM_0X: Readonly<{
|
|
|
275
308
|
/**
|
|
276
309
|
* Standard + stored. Landkarten (`vatRates`, `tipSteps`, `shortcuts`)
|
|
277
310
|
* werden je Schluessel gemischt, damit neue Saetze beim Altbestand ankommen;
|
|
278
|
-
* Schluessel, die der Standard nicht fuehrt, bleiben draussen
|
|
311
|
+
* Schluessel, die der Standard nicht fuehrt, bleiben draussen, ausser einer
|
|
312
|
+
* optionalen Geraete-Einstellung ([POS_DEVICE_OPTIONAL_FIELDS]) mit gueltiger
|
|
313
|
+
* Kennung und einem optionalen Betriebs-Schalter
|
|
314
|
+
* ([POS_BUSINESS_OPTIONAL_FIELDS]) als Wahrheitswert.
|
|
279
315
|
*
|
|
280
316
|
* **Immer** (unabhaengig davon, welches Standard-Objekt uebergeben wird, auch
|
|
281
317
|
* eine Kopie oder das einer zweiten Paketkopie) faellt ein Wert der inneren
|
package/dist/cjs/pos/settings.js
CHANGED
|
@@ -13,8 +13,10 @@
|
|
|
13
13
|
* bis die Buchung geklaert ist (Spec kachel-kasse § 9).
|
|
14
14
|
*/
|
|
15
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
exports._ALTFORM_0X = exports.POS_DEVICE_VALUES = exports.POS_BUSINESS_VALUES = exports.POS_DEVICE_DEFAULTS = exports.POS_BUSINESS_DEFAULTS = exports.POS_SHORTCUT_SHARED_PAIRS = exports.POS_SHORTCUT_DEFAULTS = exports.POS_SHORTCUT_ACTIONS = exports.DONE_SCREEN_SECONDS = exports.WATERMARK_SCALE = exports.LOGO_SCALE = exports.WATERMARK_STRENGTH = exports.WATERMARK_SIDE = exports.DISCOUNT = exports.AUTO_LOGOUT_MINUTES = exports.TILE_STYLE = exports.SETTINGS_FONT_SIZE = exports.LOGO_SIZE = exports.QR_MODE = exports.DRAWER_AUTO_OPEN = exports.CUT = exports.CODE_PAGE = exports.PAPER_SIZE = exports.TERMINAL_TYPE = exports.TERMINAL_VIA = exports.PRINTER_TYPE = exports.TILE_HEIGHT = exports.CATEGORY_POSITION = exports.LAYOUT = exports.RECEIPT_OUTPUT = exports.CARD_PROVIDER = exports.CHECKOUT_MODE = exports.TIP_MODE = exports.QUANTITY = exports.WATERMARK = exports.FONT_SIZE = exports.THEME = void 0;
|
|
16
|
+
exports._ALTFORM_0X = exports.POS_DEVICE_VALUES = exports.POS_BUSINESS_VALUES = exports.POS_BUSINESS_OPTIONAL_FIELDS = exports.POS_DEVICE_OPTIONAL_FIELDS = exports.POS_DEVICE_DEFAULTS = exports.POS_BUSINESS_DEFAULTS = exports.POS_SHORTCUT_SHARED_PAIRS = exports.POS_SHORTCUT_DEFAULTS = exports.POS_SHORTCUT_ACTIONS = exports.DONE_SCREEN_SECONDS = exports.WATERMARK_SCALE = exports.LOGO_SCALE = exports.WATERMARK_STRENGTH = exports.WATERMARK_SIDE = exports.DISCOUNT = exports.AUTO_LOGOUT_MINUTES = exports.TILE_STYLE = exports.SETTINGS_FONT_SIZE = exports.LOGO_SIZE = exports.QR_MODE = exports.DRAWER_AUTO_OPEN = exports.CUT = exports.CODE_PAGE = exports.PAPER_SIZE = exports.TERMINAL_TYPE = exports.TERMINAL_VIA = exports.PRINTER_TYPE = exports.TILE_HEIGHT = exports.CATEGORY_POSITION = exports.LAYOUT = exports.RECEIPT_OUTPUT = exports.CARD_PROVIDER = exports.CHECKOUT_MODE = exports.TIP_MODE = exports.QUANTITY = exports.WATERMARK = exports.FONT_SIZE = exports.THEME = void 0;
|
|
17
17
|
exports.posShortcutConflict = posShortcutConflict;
|
|
18
|
+
exports._optionalerWert = _optionalerWert;
|
|
19
|
+
exports.posTipKeptByDefault = posTipKeptByDefault;
|
|
18
20
|
exports._istAltwert0x = _istAltwert0x;
|
|
19
21
|
exports.mergePosSettings = mergePosSettings;
|
|
20
22
|
exports.sanitizePosSettings = sanitizePosSettings;
|
|
@@ -182,6 +184,33 @@ exports.POS_DEVICE_DEFAULTS = Object.freeze({
|
|
|
182
184
|
terminalIp: '', terminalPort: 8080, terminalTid: '', terminalVia: 'direct',
|
|
183
185
|
terminalType: 'none', shortcutHints: true,
|
|
184
186
|
});
|
|
187
|
+
/**
|
|
188
|
+
* Optionale Geraete-Einstellungen: ohne Standardwert, der Server sendet sie
|
|
189
|
+
* nur, wenn sie gesetzt sind (Backend `GERAET_OPTIONAL`). Sie fehlen darum in
|
|
190
|
+
* [POS_DEVICE_DEFAULTS]; [mergePosSettings] uebernimmt sie, wenn sie als
|
|
191
|
+
* Kennung kommen, und der Schreibweg nimmt sie als Kennung oder `null`
|
|
192
|
+
* (Zuordnung entfernen).
|
|
193
|
+
*/
|
|
194
|
+
exports.POS_DEVICE_OPTIONAL_FIELDS = Object.freeze(['drawerId']);
|
|
195
|
+
/** Form einer optionalen Kennung (Backend `ladeKennung`). */
|
|
196
|
+
const OPTIONALE_KENNUNG = /^[A-Za-z0-9_-]{1,64}$/;
|
|
197
|
+
/** Gilt dieser Wert fuer ein optionales Feld? Lesen: nur eine Kennung; Schreiben: auch `null`. */
|
|
198
|
+
function _optionalerWert(wert, schreiben) {
|
|
199
|
+
return (schreiben && wert === null) || (typeof wert === 'string' && OPTIONALE_KENNUNG.test(wert));
|
|
200
|
+
}
|
|
201
|
+
const OPTIONALE = new Set(exports.POS_DEVICE_OPTIONAL_FIELDS);
|
|
202
|
+
/**
|
|
203
|
+
* Optionale Betriebs-Einstellungen (Schalter): ohne Standardwert, der Server
|
|
204
|
+
* sendet sie nur, wenn sie gespeichert sind (Backend `BETRIEB_OPTIONAL`).
|
|
205
|
+
* [mergePosSettings] uebernimmt sie nur als Wahrheitswert; der Schreibweg
|
|
206
|
+
* nimmt nur `true`/`false`.
|
|
207
|
+
*/
|
|
208
|
+
exports.POS_BUSINESS_OPTIONAL_FIELDS = Object.freeze(['tipKeptByDefault']);
|
|
209
|
+
const OPTIONALE_SCHALTER = new Set(exports.POS_BUSINESS_OPTIONAL_FIELDS);
|
|
210
|
+
/** Bar-Trinkgeld „gleich behalten“ vorbelegt? Fehlt die Einstellung, gilt aus. */
|
|
211
|
+
function posTipKeptByDefault(business) {
|
|
212
|
+
return !!business && business.tipKeptByDefault === true;
|
|
213
|
+
}
|
|
185
214
|
/**
|
|
186
215
|
* Die Wertemenge je Feld, soweit das Feld eine hat: dagegen prueft der
|
|
187
216
|
* Schreibweg vor dem Senden (ein deutscher Wert wie `'nacht'` geht so gar
|
|
@@ -243,7 +272,10 @@ exports._ALTFORM_0X = Object.freeze({ werte: ALTWERTE_0X, aktionen: [...ALTAKTIO
|
|
|
243
272
|
/**
|
|
244
273
|
* Standard + stored. Landkarten (`vatRates`, `tipSteps`, `shortcuts`)
|
|
245
274
|
* werden je Schluessel gemischt, damit neue Saetze beim Altbestand ankommen;
|
|
246
|
-
* Schluessel, die der Standard nicht fuehrt, bleiben draussen
|
|
275
|
+
* Schluessel, die der Standard nicht fuehrt, bleiben draussen, ausser einer
|
|
276
|
+
* optionalen Geraete-Einstellung ([POS_DEVICE_OPTIONAL_FIELDS]) mit gueltiger
|
|
277
|
+
* Kennung und einem optionalen Betriebs-Schalter
|
|
278
|
+
* ([POS_BUSINESS_OPTIONAL_FIELDS]) als Wahrheitswert.
|
|
247
279
|
*
|
|
248
280
|
* **Immer** (unabhaengig davon, welches Standard-Objekt uebergeben wird, auch
|
|
249
281
|
* eine Kopie oder das einer zweiten Paketkopie) faellt ein Wert der inneren
|
|
@@ -256,8 +288,16 @@ function mergePosSettings(standard, stored) {
|
|
|
256
288
|
const out = JSON.parse(JSON.stringify(standard));
|
|
257
289
|
if (stored && typeof stored === 'object') {
|
|
258
290
|
for (const key of Object.keys(stored)) {
|
|
259
|
-
if (!eigen(out, key))
|
|
291
|
+
if (!eigen(out, key)) {
|
|
292
|
+
// Optionale Geraete-Einstellung (ohne Standardwert): nur als Kennung;
|
|
293
|
+
// optionaler Betriebs-Schalter: nur als Wahrheitswert.
|
|
294
|
+
const wert = stored[key];
|
|
295
|
+
if (OPTIONALE.has(key) && _optionalerWert(wert, false))
|
|
296
|
+
out[key] = wert;
|
|
297
|
+
if (OPTIONALE_SCHALTER.has(key) && typeof wert === 'boolean')
|
|
298
|
+
out[key] = wert;
|
|
260
299
|
continue;
|
|
300
|
+
}
|
|
261
301
|
const wert = stored[key];
|
|
262
302
|
const alt = out[key];
|
|
263
303
|
if (alt && typeof alt === 'object' && !Array.isArray(alt) && wert && typeof wert === 'object' && !Array.isArray(wert)) {
|