@kreiseck/kasseneck-api 1.1.0 → 1.2.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 +88 -0
- package/README.md +70 -0
- package/dist/cjs/client/aufrufe.d.ts +5 -5
- package/dist/cjs/client/aufrufe.js +21 -2
- package/dist/cjs/client/errors.d.ts +1 -1
- package/dist/cjs/client/errors.js +2 -1
- package/dist/cjs/client/receipts.d.ts +9 -1
- package/dist/cjs/client/receipts.js +18 -3
- package/dist/cjs/client/transport.d.ts +3 -3
- package/dist/cjs/client/transport.js +2 -2
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js +6 -3
- package/dist/cjs/invoice/index.d.ts +2 -2
- package/dist/cjs/invoice/index.js +3 -1
- package/dist/cjs/invoice/typen.d.ts +13 -2
- package/dist/cjs/invoice/vertrag.d.ts +10 -1
- package/dist/cjs/invoice/vertrag.js +39 -2
- package/dist/cjs/models/cancellation.d.ts +14 -2
- package/dist/cjs/models/cancellation.js +15 -1
- package/dist/cjs/models/cashregister.d.ts +3 -0
- package/dist/cjs/models/cashregister.js +1 -0
- package/dist/cjs/models/index.d.ts +1 -1
- package/dist/cjs/models/index.js +4 -2
- package/dist/cjs/models/payment-errors.d.ts +1 -1
- package/dist/cjs/models/payment-errors.js +1 -0
- package/dist/cjs/models/receipt-email.d.ts +1 -1
- package/dist/cjs/models/receipt-email.js +1 -0
- package/dist/cjs/models/receipt-errors.d.ts +1 -1
- package/dist/cjs/models/receipt-errors.js +1 -0
- package/dist/cjs/models/receipt-item.d.ts +9 -0
- package/dist/cjs/models/receipt-item.js +5 -0
- package/dist/cjs/models/receipt.d.ts +1 -1
- package/dist/cjs/models/receipt.js +6 -1
- package/dist/cjs/pos/artikel.d.ts +14 -0
- package/dist/cjs/pos/artikel.js +13 -2
- package/dist/cjs/pos/errors.d.ts +3 -3
- package/dist/cjs/pos/errors.js +6 -2
- package/dist/cjs/pos/index.d.ts +5 -2
- package/dist/cjs/pos/index.js +13 -2
- package/dist/cjs/pos/lager.d.ts +95 -0
- package/dist/cjs/pos/lager.js +160 -0
- package/dist/cjs/pos/texte.d.ts +22 -3
- package/dist/cjs/pos/texte.js +22 -6
- package/dist/cjs/printing/code-table-preview.d.ts +15 -0
- package/dist/cjs/printing/code-table-preview.js +24 -0
- package/dist/cjs/printing/index.d.ts +1 -0
- package/dist/cjs/printing/index.js +3 -1
- package/dist/cjs/receipt/code-table-test-sheet.d.ts +8 -2
- package/dist/cjs/receipt/code-table-test-sheet.js +2 -0
- package/dist/cjs/register/errors.d.ts +1 -1
- package/dist/cjs/register/errors.js +1 -0
- package/dist/cjs/register/pairing.d.ts +27 -1
- package/dist/cjs/register/pairing.js +18 -1
- package/dist/cjs/stored/draht.d.ts +4 -2
- package/dist/cjs/stored/draht.js +46 -5
- package/dist/cjs/stored/vokabular.d.ts +1 -1
- package/dist/cjs/stored/vokabular.js +5 -3
- 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 +21 -2
- package/dist/esm/client/errors.d.ts +1 -1
- package/dist/esm/client/errors.js +2 -1
- package/dist/esm/client/receipts.d.ts +9 -1
- package/dist/esm/client/receipts.js +19 -4
- package/dist/esm/client/transport.d.ts +3 -3
- package/dist/esm/client/transport.js +2 -2
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +2 -2
- package/dist/esm/invoice/index.d.ts +2 -2
- package/dist/esm/invoice/index.js +1 -1
- package/dist/esm/invoice/typen.d.ts +13 -2
- package/dist/esm/invoice/vertrag.d.ts +10 -1
- package/dist/esm/invoice/vertrag.js +38 -1
- package/dist/esm/models/cancellation.d.ts +14 -2
- package/dist/esm/models/cancellation.js +13 -0
- package/dist/esm/models/cashregister.d.ts +3 -0
- package/dist/esm/models/cashregister.js +1 -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 +1 -0
- package/dist/esm/models/receipt-email.d.ts +1 -1
- package/dist/esm/models/receipt-email.js +1 -0
- package/dist/esm/models/receipt-errors.d.ts +1 -1
- package/dist/esm/models/receipt-errors.js +1 -0
- package/dist/esm/models/receipt-item.d.ts +9 -0
- package/dist/esm/models/receipt-item.js +5 -0
- package/dist/esm/models/receipt.d.ts +1 -1
- package/dist/esm/models/receipt.js +6 -1
- package/dist/esm/pos/artikel.d.ts +14 -0
- package/dist/esm/pos/artikel.js +13 -3
- package/dist/esm/pos/errors.d.ts +3 -3
- package/dist/esm/pos/errors.js +6 -2
- package/dist/esm/pos/index.d.ts +5 -2
- package/dist/esm/pos/index.js +6 -2
- package/dist/esm/pos/lager.d.ts +95 -0
- package/dist/esm/pos/lager.js +154 -0
- package/dist/esm/pos/texte.d.ts +22 -3
- package/dist/esm/pos/texte.js +22 -6
- package/dist/esm/printing/code-table-preview.d.ts +15 -0
- package/dist/esm/printing/code-table-preview.js +21 -0
- package/dist/esm/printing/index.d.ts +1 -0
- package/dist/esm/printing/index.js +1 -0
- package/dist/esm/receipt/code-table-test-sheet.d.ts +8 -2
- package/dist/esm/receipt/code-table-test-sheet.js +2 -0
- package/dist/esm/register/errors.d.ts +1 -1
- package/dist/esm/register/errors.js +1 -0
- package/dist/esm/register/pairing.d.ts +27 -1
- package/dist/esm/register/pairing.js +17 -1
- package/dist/esm/stored/draht.d.ts +4 -2
- package/dist/esm/stored/draht.js +45 -4
- package/dist/esm/stored/vokabular.d.ts +1 -1
- package/dist/esm/stored/vokabular.js +5 -3
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/fixtures/code-table-preview.json +14 -0
- package/fixtures/expected/code-table-test-sheet.lines.json +22 -4
- package/fixtures/expected/code-table-test-sheet.mm58.hex +58 -55
- package/fixtures/expected/code-table-test-sheet.mm80.hex +59 -56
- package/fixtures/hobex-hps-codes.json +1 -1
- package/fixtures/invoice-api-examples/cancel-error-return-disposition.json +17 -0
- package/fixtures/invoice-api-examples/credit-error-return-disposition.json +26 -0
- package/fixtures/invoice-api-examples/credit-return-disposition.json +23 -0
- package/fixtures/invoice-api-examples/issue-error-return-disposition.json +25 -0
- package/fixtures/invoice-api-examples/issue-error-stock-id.json +27 -0
- package/fixtures/invoice-api-examples/issue-stock.json +22 -0
- package/fixtures/invoice-api.schema.json +37 -1
- package/fixtures/invoice-texts.json +1 -1
- package/fixtures/pos-texts.json +25 -4
- package/fixtures/surface.json +48 -4
- 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 +662 -3
- package/fixtures/v3/antworten/rechnungen.json +1 -1
- package/fixtures/v3/antworten/storno.json +1 -1
- package/fixtures/v3/stored/belege.json +1 -1
- package/fixtures/v3/stored/kasse.json +58 -3
- package/fixtures/v3/stored/rechnungen.json +1 -1
- package/fixtures/v3/v3-vokabular.json +249 -16
- package/fixtures/v3/zahlbetrag-faelle.json +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { KasseneckValidationError } from '../client/errors.js';
|
|
2
|
+
import { liste } from './artikel.js';
|
|
3
|
+
/**
|
|
4
|
+
* Lager an der Kasse (Lager-Kern Stufe 2, Backend lager-endpoints.js):
|
|
5
|
+
* Standorte, Bestand und der Standort der Kasse. Alle drei Aufrufe gibt es
|
|
6
|
+
* nur ueber den Kassenweg `/api/v3` (registerInternal); Rechte am Server:
|
|
7
|
+
* `stockView` (lesen), `stockCosts` (Werte), `stockLocation` (Standort setzen).
|
|
8
|
+
*
|
|
9
|
+
* **Ganzzahlen:** Mengen sind Tausendstel der Basiseinheit (`1000` = 1 Stueck,
|
|
10
|
+
* `250` = 0,250 kg), Werte ganze Cent bzw. Mikro-Euro. Nichts wird geteilt,
|
|
11
|
+
* gerundet oder geklemmt -- ein negativer Bestand (mehr verkauft als gebucht)
|
|
12
|
+
* ist eine Aussage des Servers und bleibt negativ. Eine Zahl, die keine
|
|
13
|
+
* Ganzzahl ist, oder eine fehlende Menge wird **nie** zu `0`: der Aufruf
|
|
14
|
+
* endet mit `KasseneckValidationError` (`scope: 'response'`), denn „kein
|
|
15
|
+
* Bestand“ und „Antwort kaputt“ sind verschiedene Aussagen.
|
|
16
|
+
*/
|
|
17
|
+
/** Standort-Typen (Katalog `STANDORT_TYP`), englisch wie am Draht. */
|
|
18
|
+
export const STOCK_LOCATION_TYPES = Object.freeze(['warehouse', 'store', 'vehicle', 'other']);
|
|
19
|
+
const TYPEN = new Set(STOCK_LOCATION_TYPES);
|
|
20
|
+
function antwortfehler(name, grund) {
|
|
21
|
+
return new KasseneckValidationError(name, grund, 'response');
|
|
22
|
+
}
|
|
23
|
+
const objekt = (w) => (w !== null && typeof w === 'object' && !Array.isArray(w) ? w : null);
|
|
24
|
+
/** Freitext, der fehlen darf (Name, Adressteile, Kennzeichen): leer = `null`. */
|
|
25
|
+
const textOderNull = (w) => (typeof w === 'string' && w !== '' ? w : null);
|
|
26
|
+
/**
|
|
27
|
+
* Eine Kennung, die da sein muss: ohne sie ist die Zeile nicht zuzuordnen,
|
|
28
|
+
* und ein leerer Text als `stockLocationId` setzte die Kasse zurueck.
|
|
29
|
+
*/
|
|
30
|
+
function kennung(name, pfad, w) {
|
|
31
|
+
if (typeof w !== 'string' || w === '')
|
|
32
|
+
throw antwortfehler(name, `Antwort enthaelt keine Kennung (data.${pfad} fehlt)`);
|
|
33
|
+
return w;
|
|
34
|
+
}
|
|
35
|
+
/** Eine Zahl des Servers: Ganzzahl oder Antwortfehler, nie ein Ersatzwert. */
|
|
36
|
+
function ganzzahl(name, pfad, w) {
|
|
37
|
+
if (typeof w !== 'number' || !Number.isInteger(w)) {
|
|
38
|
+
throw antwortfehler(name, `Antwort enthaelt keine ganze Zahl (data.${pfad})`);
|
|
39
|
+
}
|
|
40
|
+
return w;
|
|
41
|
+
}
|
|
42
|
+
function standort(name, e, i) {
|
|
43
|
+
const s = objekt(e) ?? {};
|
|
44
|
+
const pfad = `locations[${i}]`;
|
|
45
|
+
const a = objekt(s.address);
|
|
46
|
+
const teile = a ? { street: textOderNull(a.street), zip: textOderNull(a.zip), city: textOderNull(a.city), country: textOderNull(a.country) } : null;
|
|
47
|
+
// Eine Adresse ohne einen einzigen Teil ist keine Adresse.
|
|
48
|
+
const address = teile && Object.values(teile).some((t) => t !== null) ? teile : null;
|
|
49
|
+
return {
|
|
50
|
+
id: kennung(name, `${pfad}.id`, s.id),
|
|
51
|
+
name: typeof s.name === 'string' ? s.name : '',
|
|
52
|
+
type: typeof s.type === 'string' && TYPEN.has(s.type) ? s.type : null,
|
|
53
|
+
address,
|
|
54
|
+
licensePlate: textOderNull(s.licensePlate),
|
|
55
|
+
active: s.active !== false,
|
|
56
|
+
virtual: s.virtual === true,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function bestand(name, e, i) {
|
|
60
|
+
const b = objekt(e) ?? {};
|
|
61
|
+
const pfad = `stock[${i}]`;
|
|
62
|
+
return {
|
|
63
|
+
articleId: kennung(name, `${pfad}.articleId`, b.articleId),
|
|
64
|
+
locationId: kennung(name, `${pfad}.locationId`, b.locationId),
|
|
65
|
+
sellable: ganzzahl(name, `${pfad}.sellable`, b.sellable),
|
|
66
|
+
defective: ganzzahl(name, `${pfad}.defective`, b.defective),
|
|
67
|
+
reserved: ganzzahl(name, `${pfad}.reserved`, b.reserved),
|
|
68
|
+
available: ganzzahl(name, `${pfad}.available`, b.available),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function wert(name, e, i) {
|
|
72
|
+
const w = objekt(e) ?? {};
|
|
73
|
+
const pfad = `values[${i}]`;
|
|
74
|
+
return {
|
|
75
|
+
articleId: kennung(name, `${pfad}.articleId`, w.articleId),
|
|
76
|
+
stockValueCents: ganzzahl(name, `${pfad}.stockValueCents`, w.stockValueCents),
|
|
77
|
+
// Fehlt der Durchschnitt oder ist er null, ist die Menge 0 -- eine
|
|
78
|
+
// vorhandene, aber unbrauchbare Zahl ist dagegen ein Antwortfehler.
|
|
79
|
+
averageCostMicros: w.averageCostMicros === undefined || w.averageCostMicros === null
|
|
80
|
+
? null
|
|
81
|
+
: ganzzahl(name, `${pfad}.averageCostMicros`, w.averageCostMicros),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/** Standorte des Betriebs, samt aufgeloesten (`active: false`) und dem Hauptstandort. */
|
|
85
|
+
export async function listMyStockLocations(transport) {
|
|
86
|
+
const name = 'listMyStockLocations';
|
|
87
|
+
const daten = await transport(name);
|
|
88
|
+
return liste(daten, 'locations', name, (e, i) => standort(name, e, i));
|
|
89
|
+
}
|
|
90
|
+
/** Bestand je Artikel und Standort; Werte nur mit dem Recht `stockCosts`. */
|
|
91
|
+
export async function listMyStock(transport, options = {}) {
|
|
92
|
+
const name = 'listMyStock';
|
|
93
|
+
if (options === null || typeof options !== 'object')
|
|
94
|
+
throw new KasseneckValidationError(name, 'options muss ein Objekt sein', 'request');
|
|
95
|
+
const params = {};
|
|
96
|
+
for (const feld of ['locationId', 'articleId']) {
|
|
97
|
+
const w = options[feld];
|
|
98
|
+
if (w === undefined || w === '')
|
|
99
|
+
continue;
|
|
100
|
+
if (typeof w !== 'string')
|
|
101
|
+
throw new KasseneckValidationError(name, `${feld} muss Text sein`, 'request');
|
|
102
|
+
params[feld] = w;
|
|
103
|
+
}
|
|
104
|
+
if (options.belowMinimum !== undefined) {
|
|
105
|
+
if (typeof options.belowMinimum !== 'boolean')
|
|
106
|
+
throw new KasseneckValidationError(name, 'belowMinimum muss true oder false sein', 'request');
|
|
107
|
+
// false filtert am Server nicht; gesendet wird nur der Filter selbst.
|
|
108
|
+
if (options.belowMinimum)
|
|
109
|
+
params.belowMinimum = true;
|
|
110
|
+
}
|
|
111
|
+
const daten = await transport(name, params);
|
|
112
|
+
const stock = liste(daten, 'stock', name, (e, i) => bestand(name, e, i));
|
|
113
|
+
const roh = objekt(daten)?.values;
|
|
114
|
+
// Fehlt `values`, fehlt dem Aufrufer das Recht `stockCosts`: `null`, nie `[]`.
|
|
115
|
+
// Etwas anderes als eine Liste ist dagegen kein „kein Recht“, sondern kaputt.
|
|
116
|
+
if (roh === undefined || roh === null)
|
|
117
|
+
return { stock, values: null };
|
|
118
|
+
return { stock, values: liste(daten, 'values', name, (e, i) => wert(name, e, i)) };
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Standort der Kasse setzen -- von dort bucht der Server Verkauf und Storno
|
|
122
|
+
* ab. `stockLocationId: null` setzt zurueck (am Draht der leere Text).
|
|
123
|
+
* Fehler am Code: `location_not_found`, `location_inactive`,
|
|
124
|
+
* `cashregister_not_found`, `cashregister_not_assigned`, `not_permitted`,
|
|
125
|
+
* `module_inactive`.
|
|
126
|
+
*/
|
|
127
|
+
export async function setMyCashregisterStockLocation(transport, options) {
|
|
128
|
+
const name = 'setMyCashregisterStockLocation';
|
|
129
|
+
const ziel = options?.stockLocationId;
|
|
130
|
+
if (ziel !== null && typeof ziel !== 'string') {
|
|
131
|
+
throw new KasseneckValidationError(name, 'stockLocationId fehlt (Kennung, oder null zum Zuruecksetzen)', 'request');
|
|
132
|
+
}
|
|
133
|
+
// Leer setzt zurueck. Nur Leerraum wuerde der Server kuerzen und damit still
|
|
134
|
+
// auf den Standard-Standort zuruecksetzen: das ist kein Standort, sondern ein Fehler.
|
|
135
|
+
if (ziel !== null && ziel !== '' && ziel.trim() === '') {
|
|
136
|
+
throw new KasseneckValidationError(name, 'stockLocationId ist nur Leerraum (Kennung angeben, oder null zum Zuruecksetzen)', 'request');
|
|
137
|
+
}
|
|
138
|
+
const params = { stockLocationId: ziel === null ? '' : ziel };
|
|
139
|
+
if (options.cashregisterId !== undefined) {
|
|
140
|
+
if (typeof options.cashregisterId !== 'string' || options.cashregisterId.trim() === '') {
|
|
141
|
+
throw new KasseneckValidationError(name, 'cashregisterId ist leer', 'request');
|
|
142
|
+
}
|
|
143
|
+
params.cashregisterId = options.cashregisterId;
|
|
144
|
+
}
|
|
145
|
+
const daten = objekt(await transport(name, params));
|
|
146
|
+
if (!daten || typeof daten.cashregisterId !== 'string' || daten.cashregisterId === '') {
|
|
147
|
+
throw antwortfehler(name, 'Antwort enthaelt keine Kasse (data.cashregisterId fehlt)');
|
|
148
|
+
}
|
|
149
|
+
const stand = daten.stockLocationId;
|
|
150
|
+
if (stand !== null && stand !== undefined && typeof stand !== 'string') {
|
|
151
|
+
throw antwortfehler(name, 'Antwort enthaelt einen unbrauchbaren Standort (data.stockLocationId)');
|
|
152
|
+
}
|
|
153
|
+
return { cashregisterId: daten.cashregisterId, stockLocationId: textOderNull(stand) };
|
|
154
|
+
}
|
package/dist/esm/pos/texte.d.ts
CHANGED
|
@@ -470,10 +470,17 @@ declare const MELDUNGEN_ROH: {
|
|
|
470
470
|
readonly text: "Nichts gespeichert.";
|
|
471
471
|
};
|
|
472
472
|
readonly 'codetable.question': {
|
|
473
|
-
readonly text: "
|
|
473
|
+
readonly text: "In welcher Zeile steht kein falsches Zeichen?";
|
|
474
|
+
};
|
|
475
|
+
readonly 'codetable.question_hint': {
|
|
476
|
+
readonly text: "Lücken sind in Ordnung.";
|
|
474
477
|
};
|
|
475
478
|
readonly 'codetable.instruction': {
|
|
476
|
-
readonly text: "Die
|
|
479
|
+
readonly text: "Die Zeile, in der KEIN falsches Zeichen steht. Eine Lücke ist in Ordnung. Passen mehrere, die mit den wenigsten Lücken.";
|
|
480
|
+
};
|
|
481
|
+
readonly 'codetable.instruction_none': {
|
|
482
|
+
readonly text: "Passt keine: {number}.";
|
|
483
|
+
readonly placeholders: readonly ["number"];
|
|
477
484
|
};
|
|
478
485
|
readonly 'bluetooth.off': {
|
|
479
486
|
readonly text: "Bluetooth ist ausgeschaltet. Bitte einschalten und erneut suchen.";
|
|
@@ -974,7 +981,7 @@ declare const BESCHRIFTUNGEN_ROH: {
|
|
|
974
981
|
readonly text: "ZEICHENSATZ-TEST";
|
|
975
982
|
};
|
|
976
983
|
readonly 'codetable.reference': {
|
|
977
|
-
readonly text: "So
|
|
984
|
+
readonly text: "So sehen die Zeichen richtig aus";
|
|
978
985
|
};
|
|
979
986
|
readonly 'codetable.replacement_note': {
|
|
980
987
|
readonly text: "(Ersatz, passt immer)";
|
|
@@ -996,6 +1003,18 @@ declare const BESCHRIFTUNGEN_ROH: {
|
|
|
996
1003
|
readonly text: "Zeichensatz: Nr. {number}";
|
|
997
1004
|
readonly placeholders: readonly ["number"];
|
|
998
1005
|
};
|
|
1006
|
+
readonly 'codetable.instruction_title': {
|
|
1007
|
+
readonly text: "Welche Zeile nehmen?";
|
|
1008
|
+
};
|
|
1009
|
+
readonly 'codetable.preview_title': {
|
|
1010
|
+
readonly text: "So steht es dann am Bon:";
|
|
1011
|
+
};
|
|
1012
|
+
readonly 'codetable.apply': {
|
|
1013
|
+
readonly text: "Übernehmen";
|
|
1014
|
+
};
|
|
1015
|
+
readonly 'codetable.other_row': {
|
|
1016
|
+
readonly text: "Andere Zeile";
|
|
1017
|
+
};
|
|
999
1018
|
};
|
|
1000
1019
|
export type LabelKey = keyof typeof BESCHRIFTUNGEN_ROH;
|
|
1001
1020
|
export declare const LABELS: Record<LabelKey, TextEntry>;
|
package/dist/esm/pos/texte.js
CHANGED
|
@@ -246,9 +246,17 @@ const MELDUNGEN_ROH = {
|
|
|
246
246
|
// damit niemand einen halb eingerichteten Drucker vermutet.
|
|
247
247
|
'print.wizard_cancelled': { text: 'Nichts gespeichert.' },
|
|
248
248
|
// Zeichensatz-Test im Drucker-Wizard: das Testblatt nennt die Anleitung,
|
|
249
|
-
// der Bildschirm stellt die Frage daneben.
|
|
250
|
-
|
|
251
|
-
|
|
249
|
+
// der Bildschirm stellt die Frage daneben. Die Regel ist „kein falsches
|
|
250
|
+
// Zeichen“, nicht „erste Zeile“ und nicht „Umlaute richtig“: ein Drucker
|
|
251
|
+
// mit nur PC437 druckt Zeile 2 und 3 mit richtigen Umlauten, aber falschem
|
|
252
|
+
// € und § (╒, ⌡); richtig ist dort Zeile 4, mit Luecken fuer € und §.
|
|
253
|
+
// Am Papier steht „Lücke“ als „Luecke“ (Ersatzbuchstaben wie jeder Text
|
|
254
|
+
// ausserhalb der Testzeilen), am Bildschirm mit Umlaut.
|
|
255
|
+
'codetable.question': { text: 'In welcher Zeile steht kein falsches Zeichen?' },
|
|
256
|
+
'codetable.question_hint': { text: 'Lücken sind in Ordnung.' },
|
|
257
|
+
'codetable.instruction': { text: 'Die Zeile, in der KEIN falsches Zeichen steht. Eine Lücke ist in Ordnung. Passen mehrere, die mit den wenigsten Lücken.' },
|
|
258
|
+
// `{number}` ist die Ersatz-Zeile (6), die immer passt.
|
|
259
|
+
'codetable.instruction_none': { text: 'Passt keine: {number}.', placeholders: ['number'] },
|
|
252
260
|
'bluetooth.off': { text: 'Bluetooth ist ausgeschaltet. Bitte einschalten und erneut suchen.', only: ['app'] },
|
|
253
261
|
'bluetooth.permission_missing': { text: 'Bitte die Freigabe in den Geräte-Einstellungen erteilen.', only: ['app'] },
|
|
254
262
|
'bluetooth.search_failed': { text: 'Die Suche ist fehlgeschlagen: {reason}', placeholders: ['reason'], only: ['app'] },
|
|
@@ -561,17 +569,25 @@ const BESCHRIFTUNGEN_ROH = {
|
|
|
561
569
|
'cancellation.payment_remainder': { text: 'Rest {amount}', placeholders: ['amount'] },
|
|
562
570
|
'cancellation.difference': { text: 'Differenz' },
|
|
563
571
|
// --- Zeichensatz-Test (Testblatt und Drucker & Lade) ----------------------
|
|
564
|
-
// Das Testblatt druckt diese Texte
|
|
565
|
-
// Knoepfe am Bildschirm. `{chars}` sind die fehlenden Zeichen einer Zeile
|
|
572
|
+
// Das Testblatt druckt diese Texte mit Ersatzbuchstaben (reines ASCII);
|
|
573
|
+
// die Knoepfe stehen nur am Bildschirm. `{chars}` sind die fehlenden Zeichen einer Zeile
|
|
566
574
|
// („€“ bzw. „€ §“), `{number}` die gewaehlte Zeile (1-6).
|
|
567
575
|
'codetable.title': { text: 'ZEICHENSATZ-TEST' },
|
|
568
|
-
|
|
576
|
+
// Genau 32 Spalten: mit Doppelpunkt waeren es 33, die Ueberschrift braeche um.
|
|
577
|
+
'codetable.reference': { text: 'So sehen die Zeichen richtig aus' },
|
|
569
578
|
'codetable.replacement_note': { text: '(Ersatz, passt immer)' },
|
|
570
579
|
'codetable.missing': { text: 'ohne {chars}', placeholders: ['chars'] },
|
|
571
580
|
'codetable.print_again': { text: 'Nochmal drucken' },
|
|
572
581
|
'codetable.not_checked': { text: 'Umlaute noch nicht geprüft' },
|
|
573
582
|
'codetable.check': { text: 'Umlaute prüfen' },
|
|
574
583
|
'codetable.current': { text: 'Zeichensatz: Nr. {number}', placeholders: ['number'] },
|
|
584
|
+
// Ueberschrift der Anleitung am Testblatt.
|
|
585
|
+
'codetable.instruction_title': { text: 'Welche Zeile nehmen?' },
|
|
586
|
+
// Nach der Wahl: das Beispiel so, wie es mit der Zeile am Bon steht
|
|
587
|
+
// (`codeTablePreviewText`), dann uebernehmen oder zurueck zur Frage.
|
|
588
|
+
'codetable.preview_title': { text: 'So steht es dann am Bon:' },
|
|
589
|
+
'codetable.apply': { text: 'Übernehmen' },
|
|
590
|
+
'codetable.other_row': { text: 'Andere Zeile' },
|
|
575
591
|
};
|
|
576
592
|
export const LABELS = BESCHRIFTUNGEN_ROH;
|
|
577
593
|
/** Die Beschriftung zum Schluessel, Platzhalter ersetzt; fehlt ein Wert, wirft es wie `messageText`. */
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Die Vorschau im Drucker-Wizard: nach der Wahl einer Zeile zeigt der
|
|
3
|
+
* Bildschirm ein Beispiel so, wie es mit dieser Tabelle am Bon steht. Wer
|
|
4
|
+
* Zeile 4 (PC437) waehlt, sieht „3,50 EUR“ statt „3,50 €“, bevor er
|
|
5
|
+
* uebernimmt. Gemeinsamer Prueffall mit dem Dart-Zwilling:
|
|
6
|
+
* `fixtures/code-table-preview.json`.
|
|
7
|
+
*/
|
|
8
|
+
import { type CodeTableId } from './code-tables.js';
|
|
9
|
+
/**
|
|
10
|
+
* Das Beispiel mit den Ersetzungen der Tabelle, Zeilen durch `\n` getrennt:
|
|
11
|
+
* fehlt der Tabelle ein Zeichen, stehen seine Ersatzbuchstaben da
|
|
12
|
+
* (`pc437` -> „Käsekrainer 3,50 EUR“, `replacement` -> „Kaesekrainer 3,50 EUR“).
|
|
13
|
+
* Eine unbekannte Kennung wird gemeldet.
|
|
14
|
+
*/
|
|
15
|
+
export declare function codeTablePreviewText(table: CodeTableId): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Die Vorschau im Drucker-Wizard: nach der Wahl einer Zeile zeigt der
|
|
3
|
+
* Bildschirm ein Beispiel so, wie es mit dieser Tabelle am Bon steht. Wer
|
|
4
|
+
* Zeile 4 (PC437) waehlt, sieht „3,50 EUR“ statt „3,50 €“, bevor er
|
|
5
|
+
* uebernimmt. Gemeinsamer Prueffall mit dem Dart-Zwilling:
|
|
6
|
+
* `fixtures/code-table-preview.json`.
|
|
7
|
+
*/
|
|
8
|
+
import { codeTableById } from './code-tables.js';
|
|
9
|
+
import { escPosPrintableText } from './printable.js';
|
|
10
|
+
/** Das Beispiel: Umlaut, €, °. */
|
|
11
|
+
const BEISPIEL = ['Käsekrainer 3,50 €', 'Tee 80°'];
|
|
12
|
+
/**
|
|
13
|
+
* Das Beispiel mit den Ersetzungen der Tabelle, Zeilen durch `\n` getrennt:
|
|
14
|
+
* fehlt der Tabelle ein Zeichen, stehen seine Ersatzbuchstaben da
|
|
15
|
+
* (`pc437` -> „Käsekrainer 3,50 EUR“, `replacement` -> „Kaesekrainer 3,50 EUR“).
|
|
16
|
+
* Eine unbekannte Kennung wird gemeldet.
|
|
17
|
+
*/
|
|
18
|
+
export function codeTablePreviewText(table) {
|
|
19
|
+
codeTableById(table);
|
|
20
|
+
return BEISPIEL.map((zeile) => escPosPrintableText(zeile, table)).join('\n');
|
|
21
|
+
}
|
|
@@ -2,4 +2,5 @@ export { type PosPaperSize, type PosAlign, type PosFont, type PosCutMode, type P
|
|
|
2
2
|
export { type CodeTableId, type CodeTable, CODE_TABLES, codeTableById, codeTableFromSetting, encodeForCodeTable, } from './code-tables.js';
|
|
3
3
|
export { type QrModuleSize, type QrSizing, QR_MODULE_SIZE_CAP, QR_QUIET_ZONE_MODULES, QR_MIN_MODULE_DOTS, QR_EXCEPTION_MODULE_DOTS, QR_MAX_MODULE_DOTS, QR_PRINT_WIDTH_DOTS, qrModuleCount, qrFitsInVersion, computeQrSizing, qrSizingFor, } from './qr-groesse.js';
|
|
4
4
|
export { escPosPrintableText } from './printable.js';
|
|
5
|
+
export { codeTablePreviewText } from './code-table-preview.js';
|
|
5
6
|
export { type UsbEndpointLike, type UsbAlternateLike, type UsbInterfaceLike, type UsbConfigurationLike, type UsbTransferOutResultLike, type UsbWriterLike, type UsbIdentityLike, type UsbDeviceLike, type UsbPrinterEndpoint, type UsbPrinterConnection, USB_VENDOR_EPSON, USB_CLASS_PRINTER, UsbTimeoutError, usbDeviceKey, usbFindPrinterEndpoint, usbWriteAll, usbConnectPrinter, usbPrint, usbDisconnect, } from './webusb.js';
|
|
@@ -2,4 +2,5 @@ export { createEscPosDocument, escPosBytes, escPosReset, escPosSetGlobalCodeTabl
|
|
|
2
2
|
export { CODE_TABLES, codeTableById, codeTableFromSetting, encodeForCodeTable, } from './code-tables.js';
|
|
3
3
|
export { QR_MODULE_SIZE_CAP, QR_QUIET_ZONE_MODULES, QR_MIN_MODULE_DOTS, QR_EXCEPTION_MODULE_DOTS, QR_MAX_MODULE_DOTS, QR_PRINT_WIDTH_DOTS, qrModuleCount, qrFitsInVersion, computeQrSizing, qrSizingFor, } from './qr-groesse.js';
|
|
4
4
|
export { escPosPrintableText } from './printable.js';
|
|
5
|
+
export { codeTablePreviewText } from './code-table-preview.js';
|
|
5
6
|
export { USB_VENDOR_EPSON, USB_CLASS_PRINTER, UsbTimeoutError, usbDeviceKey, usbFindPrinterEndpoint, usbWriteAll, usbConnectPrinter, usbPrint, usbDisconnect, } from './webusb.js';
|
|
@@ -5,8 +5,14 @@
|
|
|
5
5
|
* Oben steht die Vorlage-Zeile als Rasterbild -- ein Bild druckt jeder
|
|
6
6
|
* Drucker gleich, egal welche Tabelle er gerade hat. Darunter je Tabelle des
|
|
7
7
|
* Katalogs eine Zeile mit ihrer Nummer (gross), umgeschaltet mit `ESC t n`
|
|
8
|
-
* und mit den Bytes dieser Tabelle.
|
|
9
|
-
*
|
|
8
|
+
* und mit den Bytes dieser Tabelle. Richtig ist die Zeile ohne falsches
|
|
9
|
+
* Zeichen; eine Luecke (Zeichen fehlt der Tabelle) ist in Ordnung, bei
|
|
10
|
+
* mehreren die mit den wenigsten Luecken, sonst Zeile 6 (Ersatzbuchstaben).
|
|
11
|
+
* Nicht „die erste Zeile mit richtigen Umlauten“: ein Drucker mit nur PC437
|
|
12
|
+
* druckt Zeile 2 und 3 mit richtigen Umlauten, aber falschem € und §.
|
|
13
|
+
*
|
|
14
|
+
* Alles ausserhalb der Testzeilen steht mit Ersatzbuchstaben (reines ASCII),
|
|
15
|
+
* auch die Anleitung: „Lücke“ aus dem Katalog steht am Blatt als „Luecke“.
|
|
10
16
|
*
|
|
11
17
|
* Bildschirm und Papier zeigen dasselbe Blatt: `codeTableTestSheet` liefert
|
|
12
18
|
* es im Zeilenmodell des Beleg-Blatts (`ReceiptSheet`), `codeTableTestSheetBytes`
|
|
@@ -87,7 +87,9 @@ function blattBauen(options) {
|
|
|
87
87
|
bloecke.push(zeile(einzug + t));
|
|
88
88
|
bloecke.push(zeile(einzug + nurAscii(labelText('codetable.replacement_note'))));
|
|
89
89
|
bloecke.push(doppelt);
|
|
90
|
+
bloecke.push(...zeilen(labelText('codetable.instruction_title'), true));
|
|
90
91
|
bloecke.push(...zeilen(messageText('codetable.instruction')));
|
|
92
|
+
bloecke.push(...zeilen(messageText('codetable.instruction_none', { number: ersatz.number })));
|
|
91
93
|
bloecke.push(doppelt);
|
|
92
94
|
return {
|
|
93
95
|
blatt: {
|
|
@@ -22,7 +22,7 @@ import { KasseneckApiError } from '../client/errors.js';
|
|
|
22
22
|
* ueber `KasseneckApiError.code` lesbar; die Kasse braucht dafuer einen
|
|
23
23
|
* Rueckfallzweig.
|
|
24
24
|
*/
|
|
25
|
-
export declare const REGISTER_ERROR_CODES: readonly ["account_not_found", "admin_required", "cashregister_in_use", "cashregister_not_assigned", "cashregister_not_found", "cashregister_token_invalid", "cashregister_token_missing", "device_bound_elsewhere", "device_not_found", "device_not_paired", "device_takeover_required", "dialect_mismatch", "internal_translation_error", "licenses_exhausted", "live_not_enabled", "location_outside", "location_required", "login_failed", "login_mode_select_user", "login_unavailable", "method_not_allowed", "mfa_required", "not_found", "pairing_code_expired", "pairing_code_unknown", "pairing_code_used", "pairing_failed", "register_user_no_business", "register_user_not_allowed", "register_user_not_found", "register_user_only", "response_translation_failed", "session_ended", "session_expired", "session_not_running", "session_other_cashregister", "too_many_attempts", "unauthorized", "user_disabled", "user_verification_failed", "validation", "route_missing"];
|
|
25
|
+
export declare const REGISTER_ERROR_CODES: readonly ["account_not_found", "admin_required", "api_not_approved", "cashregister_in_use", "cashregister_not_assigned", "cashregister_not_found", "cashregister_token_invalid", "cashregister_token_missing", "device_bound_elsewhere", "device_not_found", "device_not_paired", "device_takeover_required", "dialect_mismatch", "internal_translation_error", "licenses_exhausted", "live_not_enabled", "location_outside", "location_required", "login_failed", "login_mode_select_user", "login_unavailable", "method_not_allowed", "mfa_required", "not_found", "pairing_code_expired", "pairing_code_unknown", "pairing_code_used", "pairing_failed", "register_user_no_business", "register_user_not_allowed", "register_user_not_found", "register_user_only", "response_translation_failed", "session_ended", "session_expired", "session_not_running", "session_other_cashregister", "too_many_attempts", "unauthorized", "user_disabled", "user_verification_failed", "validation", "route_missing"];
|
|
26
26
|
export type RegisterErrorCode = typeof REGISTER_ERROR_CODES[number];
|
|
27
27
|
export declare function isRegisterErrorCode(value: unknown): value is RegisterErrorCode;
|
|
28
28
|
/** Der Code eines geworfenen Fehlers, wenn es einer der Kassen-Anmeldung ist; sonst `undefined`. */
|
|
@@ -26,6 +26,7 @@ import { feldfehlerVon } from '../client/fehlercodes.js';
|
|
|
26
26
|
export const REGISTER_ERROR_CODES = Object.freeze([
|
|
27
27
|
'account_not_found',
|
|
28
28
|
'admin_required',
|
|
29
|
+
'api_not_approved',
|
|
29
30
|
'cashregister_in_use',
|
|
30
31
|
'cashregister_not_assigned',
|
|
31
32
|
'cashregister_not_found',
|
|
@@ -137,10 +137,12 @@ export interface RegisterDeviceUsers {
|
|
|
137
137
|
* nennt den Grund als Menschentext (ausser Betrieb, keine Signaturkarte,
|
|
138
138
|
* Startbeleg fehlt): die Kasse sperrt das Kassieren VOR dem ersten Beleg
|
|
139
139
|
* statt an createReceipt zu scheitern. Fehlt das Feld, gilt bereit.
|
|
140
|
+
* `stockLocationId`: Lager-Standort der Kasse, fehlt = Standard-Standort.
|
|
140
141
|
*/
|
|
141
142
|
cashregister?: {
|
|
142
143
|
ready: boolean;
|
|
143
144
|
reason?: string | null;
|
|
145
|
+
stockLocationId?: string;
|
|
144
146
|
};
|
|
145
147
|
/** Das Geraet haengt an der Test-Umgebung des Betriebs. */
|
|
146
148
|
testEnvironment: boolean;
|
|
@@ -179,6 +181,24 @@ export interface RegisterUserPerms {
|
|
|
179
181
|
discount?: boolean;
|
|
180
182
|
/** Trinkgeld anderen zuweisen. */
|
|
181
183
|
tipAssign?: boolean;
|
|
184
|
+
/**
|
|
185
|
+
* Lager: Standorte und Mengen sehen (listMyStockLocations, listMyStock).
|
|
186
|
+
* Fehlt das Recht, gilt es als erteilt – anders als alle anderen
|
|
187
|
+
* (siehe [stockViewOf]); ein ausdrueckliches `false` sperrt.
|
|
188
|
+
*/
|
|
189
|
+
stockView?: boolean;
|
|
190
|
+
/** Lager: Einkaufswerte sehen (`values` in listMyStock); gibt nur der Inhaber frei. */
|
|
191
|
+
stockCosts?: boolean;
|
|
192
|
+
/** Lager: Wareneingang, Umbuchen. */
|
|
193
|
+
stockMove?: boolean;
|
|
194
|
+
/** Lager: Abgang, Zustand, Gegenbuchung. */
|
|
195
|
+
stockLoss?: boolean;
|
|
196
|
+
/** Inventur: zaehlen. */
|
|
197
|
+
stocktakeCount?: boolean;
|
|
198
|
+
/** Inventur: abschliessen. */
|
|
199
|
+
stocktakeClose?: boolean;
|
|
200
|
+
/** Standort der Kasse waehlen (setMyCashregisterStockLocation). */
|
|
201
|
+
stockLocation?: boolean;
|
|
182
202
|
[weiteresRecht: string]: boolean | RegisterScope | undefined;
|
|
183
203
|
}
|
|
184
204
|
/**
|
|
@@ -189,10 +209,16 @@ export interface RegisterUserPerms {
|
|
|
189
209
|
* nicht fuehrt (Tippfehler, umbenanntes Recht), kommt hier nicht durch.
|
|
190
210
|
* Die Gegenrichtung schliesst [_RechteVollstaendig] direkt darunter.
|
|
191
211
|
*/
|
|
192
|
-
export declare const REGISTER_PERMS: readonly ["sell", "cancel", "articles", "layout", "reports", "takeover", "cancelScope", "receiptsScope", "drawer", "discount", "tipAssign"];
|
|
212
|
+
export declare const REGISTER_PERMS: readonly ["sell", "cancel", "articles", "layout", "reports", "takeover", "cancelScope", "receiptsScope", "drawer", "discount", "tipAssign", "stockView", "stockCosts", "stockMove", "stockLoss", "stocktakeCount", "stocktakeClose", "stockLocation"];
|
|
193
213
|
/** Reichweite lesen, mit der Migration des Backends (register-auth.js). */
|
|
194
214
|
export declare function cancelScopeOf(perms: RegisterUserPerms | null | undefined): RegisterScope;
|
|
195
215
|
export declare function receiptsScopeOf(perms: RegisterUserPerms | null | undefined): RegisterScope;
|
|
216
|
+
/**
|
|
217
|
+
* Darf der Benutzer Standorte und Mengen sehen? Wie im Backend (lager-core):
|
|
218
|
+
* ohne Schluessel gilt `stockView` als erteilt, ein ausdrueckliches `false`
|
|
219
|
+
* sperrt; alle anderen Lager-Rechte gelten ohne Schluessel als verweigert.
|
|
220
|
+
*/
|
|
221
|
+
export declare function stockViewOf(perms: RegisterUserPerms | null | undefined): boolean;
|
|
196
222
|
/** Der angemeldete Kassen-Benutzer. */
|
|
197
223
|
export interface RegisterUser {
|
|
198
224
|
id: string;
|
|
@@ -49,6 +49,7 @@ const ohneAnmeldung = () => ({ headers: {}, params: {} });
|
|
|
49
49
|
export const REGISTER_PERMS = [
|
|
50
50
|
'sell', 'cancel', 'articles', 'layout', 'reports', 'takeover',
|
|
51
51
|
'cancelScope', 'receiptsScope', 'drawer', 'discount', 'tipAssign',
|
|
52
|
+
'stockView', 'stockCosts', 'stockMove', 'stockLoss', 'stocktakeCount', 'stocktakeClose', 'stockLocation',
|
|
52
53
|
];
|
|
53
54
|
/** Reichweite lesen, mit der Migration des Backends (register-auth.js). */
|
|
54
55
|
export function cancelScopeOf(perms) {
|
|
@@ -65,6 +66,16 @@ export function receiptsScopeOf(perms) {
|
|
|
65
66
|
return 'all';
|
|
66
67
|
return ['none', 'own', 'all'].includes(perms.receiptsScope) ? perms.receiptsScope : 'none';
|
|
67
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Darf der Benutzer Standorte und Mengen sehen? Wie im Backend (lager-core):
|
|
71
|
+
* ohne Schluessel gilt `stockView` als erteilt, ein ausdrueckliches `false`
|
|
72
|
+
* sperrt; alle anderen Lager-Rechte gelten ohne Schluessel als verweigert.
|
|
73
|
+
*/
|
|
74
|
+
export function stockViewOf(perms) {
|
|
75
|
+
if (!perms)
|
|
76
|
+
return false;
|
|
77
|
+
return perms.stockView === undefined ? true : perms.stockView === true;
|
|
78
|
+
}
|
|
68
79
|
/**
|
|
69
80
|
* Geraet koppeln: der Kopplungs-Code wird gegen den dauerhaften Ausweis dieses
|
|
70
81
|
* Geraets getauscht. **Ohne Anmeldung** — der Code ist der Nachweis.
|
|
@@ -199,7 +210,12 @@ function kasseBereit(wert) {
|
|
|
199
210
|
const roh = wert;
|
|
200
211
|
if (typeof roh['ready'] !== 'boolean')
|
|
201
212
|
return undefined;
|
|
202
|
-
|
|
213
|
+
const standort = roh['stockLocationId'];
|
|
214
|
+
return {
|
|
215
|
+
ready: roh['ready'],
|
|
216
|
+
reason: typeof roh['reason'] === 'string' ? roh['reason'] : null,
|
|
217
|
+
...(typeof standort === 'string' && standort !== '' ? { stockLocationId: standort } : {}),
|
|
218
|
+
};
|
|
203
219
|
}
|
|
204
220
|
/** Die Regel aus der Antwort — oder `null`, wenn keine brauchbare kommt. */
|
|
205
221
|
function regel(wert) {
|
|
@@ -10,10 +10,12 @@ export declare function regel(eintrag: SchemaEintrag): {
|
|
|
10
10
|
};
|
|
11
11
|
/** Innere Namen einer Schema-Ebene (was der Server innen an dieser Stelle kennt). */
|
|
12
12
|
export declare function innereNamen(schema: SchemaObjekt): Map<string, string>;
|
|
13
|
+
/** Rueckgabe-Wahl innen -> aussen (Katalog RUECKGABE; stored.test.ts vergleicht mit dem Vertrag). */
|
|
14
|
+
export declare const _RUECKGABE_NACH_AUSSEN: Readonly<Record<string, string>>;
|
|
13
15
|
/**
|
|
14
16
|
* Ein Belegdokument, wie Handler und Rand es vor der Uebersetzung sehen:
|
|
15
|
-
* ohne Storno-Marke (storno-core.
|
|
16
|
-
* ohneStornoMarke). Alles andere bleibt woertlich, auch `pruefangaben` im
|
|
17
|
+
* ohne Storno-Marke und Lager-Standort (storno-core.ohneInterneBelegFelder,
|
|
18
|
+
* Rand ohneStornoMarke). Alles andere bleibt woertlich, auch `pruefangaben` im
|
|
17
19
|
* Beleg selbst (der Server reicht sie so durch). Wirft, wenn es kein
|
|
18
20
|
* Belegdokument ist.
|
|
19
21
|
*/
|
package/dist/esm/stored/draht.js
CHANGED
|
@@ -81,7 +81,7 @@ const aeussereWerte = (name) => new Set(Object.values(KATALOGE[name] ?? {}));
|
|
|
81
81
|
/**
|
|
82
82
|
* Interne Marke der Storno-Reservierung: `stornoMarke` am Storno-Beleg,
|
|
83
83
|
* `marke` im Bezug und in `cancellations[]`. Handler
|
|
84
|
-
* (storno-core.
|
|
84
|
+
* (storno-core.ohneInterneBelegFelder) und Rand (ohneStornoMarke) nehmen sie
|
|
85
85
|
* heraus; der Vertrag nennt die Namen nicht (nur `$function: belegJeKanal`).
|
|
86
86
|
*/
|
|
87
87
|
const STORNO_MARKE = 'stornoMarke';
|
|
@@ -92,6 +92,44 @@ const ohneMarke = (o) => {
|
|
|
92
92
|
const { [MARKE]: _m, ...rest } = o;
|
|
93
93
|
return rest;
|
|
94
94
|
};
|
|
95
|
+
/**
|
|
96
|
+
* Interne Dokumentfelder eines Belegs, die keine Antwort traegt (Zwilling von
|
|
97
|
+
* storno-core.INTERNE_BELEG_FELDER): der Lager-Standort der Kasse, den
|
|
98
|
+
* createReceipt fuer die Lagerbuchung an den Beleg kopiert.
|
|
99
|
+
*/
|
|
100
|
+
const INTERNE_BELEG_FELDER = ['lagerStandortId'];
|
|
101
|
+
/** Rueckgabe-Wahl innen -> aussen (Katalog RUECKGABE; stored.test.ts vergleicht mit dem Vertrag). */
|
|
102
|
+
export const _RUECKGABE_NACH_AUSSEN = Object.freeze({ lager: 'restock', defekt: 'defective', entsorgt: 'disposed' });
|
|
103
|
+
/**
|
|
104
|
+
* Zwilling von `rueckgabeUmbenennen` (Rand): `rueckgabe` heisst aussen
|
|
105
|
+
* `returnDisposition`, an Ort und Stelle; ein Wert ausserhalb des Katalogs
|
|
106
|
+
* faellt weg (der Server schreibt dafuer eine Warnzeile).
|
|
107
|
+
*/
|
|
108
|
+
function rueckgabeUmbenennen(o) {
|
|
109
|
+
if (!istObjekt(o) || !hat(o, 'rueckgabe'))
|
|
110
|
+
return o;
|
|
111
|
+
const raus = {};
|
|
112
|
+
for (const [k, w] of Object.entries(o)) {
|
|
113
|
+
if (k !== 'rueckgabe') {
|
|
114
|
+
raus[k] = w;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (typeof w === 'string' && hat(_RUECKGABE_NACH_AUSSEN, w))
|
|
118
|
+
raus.returnDisposition = _RUECKGABE_NACH_AUSSEN[w];
|
|
119
|
+
}
|
|
120
|
+
return raus;
|
|
121
|
+
}
|
|
122
|
+
const zeilenMitRueckgabe = (items) => (Array.isArray(items) ? items.map(rueckgabeUmbenennen) : items);
|
|
123
|
+
/** Zwilling von `belegRueckgabeNachAussen`: Storno-Zeilen und Eintraege in `cancellations[]`. */
|
|
124
|
+
function belegRueckgabeNachAussen(beleg) {
|
|
125
|
+
const raus = { ...beleg };
|
|
126
|
+
if (Array.isArray(beleg.items))
|
|
127
|
+
raus.items = zeilenMitRueckgabe(beleg.items);
|
|
128
|
+
if (Array.isArray(beleg.cancellations)) {
|
|
129
|
+
raus.cancellations = beleg.cancellations.map((c) => (istObjekt(c) && Array.isArray(c.items) ? { ...c, items: zeilenMitRueckgabe(c.items) } : c));
|
|
130
|
+
}
|
|
131
|
+
return raus;
|
|
132
|
+
}
|
|
95
133
|
/**
|
|
96
134
|
* Zwilling von `beleg-pruefangaben.alsIso`: leer (auch 0, '') -> null;
|
|
97
135
|
* Firestore-Zeitstempel, Zahl oder Zeichenkette -> ISO-Zeitpunkt in UTC;
|
|
@@ -109,8 +147,8 @@ function alsIso(ts) {
|
|
|
109
147
|
}
|
|
110
148
|
/**
|
|
111
149
|
* Ein Belegdokument, wie Handler und Rand es vor der Uebersetzung sehen:
|
|
112
|
-
* ohne Storno-Marke (storno-core.
|
|
113
|
-
* ohneStornoMarke). Alles andere bleibt woertlich, auch `pruefangaben` im
|
|
150
|
+
* ohne Storno-Marke und Lager-Standort (storno-core.ohneInterneBelegFelder,
|
|
151
|
+
* Rand ohneStornoMarke). Alles andere bleibt woertlich, auch `pruefangaben` im
|
|
114
152
|
* Beleg selbst (der Server reicht sie so durch). Wirft, wenn es kein
|
|
115
153
|
* Belegdokument ist.
|
|
116
154
|
*/
|
|
@@ -119,6 +157,8 @@ export function _storedReceiptInner(doc, functionName) {
|
|
|
119
157
|
throw new KasseneckValidationError(functionName, 'Kein Belegdokument (receiptId fehlt)', 'response');
|
|
120
158
|
}
|
|
121
159
|
const { [STORNO_MARKE]: _s, ...beleg } = doc;
|
|
160
|
+
for (const feld of INTERNE_BELEG_FELDER)
|
|
161
|
+
delete beleg[feld];
|
|
122
162
|
if (hat(beleg, 'cancellationOf'))
|
|
123
163
|
beleg.cancellationOf = ohneMarke(beleg.cancellationOf);
|
|
124
164
|
if (Array.isArray(beleg.cancellations))
|
|
@@ -140,7 +180,8 @@ export function pruefangabenDerHuelle(p) {
|
|
|
140
180
|
*/
|
|
141
181
|
export function _receiptEnvelopeToWire(huelle) {
|
|
142
182
|
const schema = SCHEMAS.getReceipt;
|
|
143
|
-
|
|
183
|
+
const draht = werteNachAussen(schluesselNachAussen(huelle, schema.data), schema.werte);
|
|
184
|
+
return istObjekt(draht.receipt) ? { ...draht, receipt: belegRueckgabeNachAussen(draht.receipt) } : draht;
|
|
144
185
|
}
|
|
145
186
|
/**
|
|
146
187
|
* Ein Belegdokument (`users/{uid}/cashregisters/{id}/receipts/{id}`) in der
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Fingerabdruck des Vertrags-Exports, aus dem diese Datei stammt (`_quelle.sha256`). */
|
|
2
|
-
export declare const VOKABULAR_QUELLE = "
|
|
2
|
+
export declare const VOKABULAR_QUELLE = "b1049e2f65e9261cf8f729481d9ce1e5afda2cf620333f38ae6bf1afb36c8712";
|
|
3
3
|
/** Schema-Notation des Vertrags: Blatt 'aussen': 'innen', Objekt { __: 'innen', ... }, Liste [ { __: 'innen', ... } ]. */
|
|
4
4
|
export type SchemaEintrag = string | SchemaObjekt | readonly [SchemaObjekt];
|
|
5
5
|
export interface SchemaObjekt {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Erzeugt von scripts/stored-vokabular.mjs aus fixtures/v3/v3-vokabular.json.
|
|
2
2
|
// Nicht von Hand aendern: test/stored.test.ts vergleicht mit dem Vertrag.
|
|
3
3
|
/** Fingerabdruck des Vertrags-Exports, aus dem diese Datei stammt (`_quelle.sha256`). */
|
|
4
|
-
export const VOKABULAR_QUELLE = "
|
|
4
|
+
export const VOKABULAR_QUELLE = "b1049e2f65e9261cf8f729481d9ce1e5afda2cf620333f38ae6bf1afb36c8712";
|
|
5
5
|
/** Schema je Endpunkt (aussen -> innen) und Wertverweise auf die Kataloge. */
|
|
6
6
|
export const SCHEMAS = {
|
|
7
7
|
"getReceipt": {
|
|
@@ -219,7 +219,8 @@ export const SCHEMAS = {
|
|
|
219
219
|
"__": "kasse",
|
|
220
220
|
"visible": "sichtbar",
|
|
221
221
|
"sort": "sort"
|
|
222
|
-
}
|
|
222
|
+
},
|
|
223
|
+
"stockLocationIds": "standorte"
|
|
223
224
|
}
|
|
224
225
|
]
|
|
225
226
|
},
|
|
@@ -256,7 +257,8 @@ export const ARTIKEL_FELDER = [
|
|
|
256
257
|
"revenueGroupId",
|
|
257
258
|
"active",
|
|
258
259
|
"groupId",
|
|
259
|
-
"tile"
|
|
260
|
+
"tile",
|
|
261
|
+
"stockLocationIds"
|
|
260
262
|
];
|
|
261
263
|
/** Wertkataloge innen (deutsch) -> aussen (englisch). */
|
|
262
264
|
export const KATALOGE = {
|
package/dist/esm/version.d.ts
CHANGED
package/dist/esm/version.js
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"sample": [
|
|
3
|
+
"Käsekrainer 3,50 €",
|
|
4
|
+
"Tee 80°"
|
|
5
|
+
],
|
|
6
|
+
"tables": {
|
|
7
|
+
"wpc1252": "Käsekrainer 3,50 €\nTee 80°",
|
|
8
|
+
"pc858": "Käsekrainer 3,50 €\nTee 80°",
|
|
9
|
+
"pc850": "Käsekrainer 3,50 EUR\nTee 80°",
|
|
10
|
+
"pc437": "Käsekrainer 3,50 EUR\nTee 80°",
|
|
11
|
+
"iso8859_15": "Käsekrainer 3,50 €\nTee 80°",
|
|
12
|
+
"replacement": "Kaesekrainer 3,50 EUR\nTee 80Grad"
|
|
13
|
+
}
|
|
14
|
+
}
|