@kreiseck/kasseneck-api 1.1.1 → 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 +56 -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/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/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/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 +1 -1
- 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
|
@@ -16,7 +16,7 @@ import { KasseneckApiError } from '../client/errors.js';
|
|
|
16
16
|
* ...) stehen in [PAYMENT_ERROR_CODES]. Ein Code ausserhalb bleibt ueber
|
|
17
17
|
* `KasseneckApiError.code` lesbar.
|
|
18
18
|
*/
|
|
19
|
-
export declare const RECEIPT_ERROR_CODES: readonly ["cancellation_reference_unavailable", "cashregister_closed", "cashregister_decommissioned", "final_receipt_expired", "final_receipt_not_allowed", "module_inactive", "not_permitted", "receipt_limit_exceeded", "receipt_not_found", "receipt_outcome_unknown", "receipt_type_invalid", "signature_incomplete", "signature_missing", "signing_failed", "small_business_vat_not_allowed", "tip_invalid", "tip_not_allowed", "tip_recipient_unknown", "validation", "account_not_found", "admin_required", "cashregister_not_assigned", "cashregister_not_found", "cashregister_token_invalid", "cashregister_token_missing", "dialect_mismatch", "internal_translation_error", "live_not_enabled", "method_not_allowed", "mfa_required", "not_found", "register_user_no_business", "register_user_not_allowed", "register_user_not_found", "response_translation_failed", "session_expired", "session_other_cashregister", "unauthorized", "user_disabled", "user_verification_failed", "route_missing", "response_unreadable"];
|
|
19
|
+
export declare const RECEIPT_ERROR_CODES: readonly ["cancellation_reference_unavailable", "cashregister_closed", "cashregister_decommissioned", "final_receipt_expired", "final_receipt_not_allowed", "module_inactive", "not_permitted", "receipt_limit_exceeded", "receipt_not_found", "receipt_outcome_unknown", "receipt_type_invalid", "signature_incomplete", "signature_missing", "signing_failed", "small_business_vat_not_allowed", "tip_invalid", "tip_not_allowed", "tip_recipient_unknown", "validation", "account_not_found", "admin_required", "api_not_approved", "cashregister_not_assigned", "cashregister_not_found", "cashregister_token_invalid", "cashregister_token_missing", "dialect_mismatch", "internal_translation_error", "live_not_enabled", "method_not_allowed", "mfa_required", "not_found", "register_user_no_business", "register_user_not_allowed", "register_user_not_found", "response_translation_failed", "session_expired", "session_other_cashregister", "unauthorized", "user_disabled", "user_verification_failed", "route_missing", "response_unreadable"];
|
|
20
20
|
export type ReceiptErrorCode = (typeof RECEIPT_ERROR_CODES)[number];
|
|
21
21
|
export declare function isReceiptErrorCode(value: unknown): value is ReceiptErrorCode;
|
|
22
22
|
/** Der Code eines geworfenen Fehlers, wenn er in [RECEIPT_ERROR_CODES] steht; sonst `undefined`. */
|
|
@@ -39,6 +39,7 @@ export const RECEIPT_ERROR_CODES = Object.freeze([
|
|
|
39
39
|
// Anmeldung und Rand (errorCodes.auth ohne Partner-Zugang, errorCodes.edge)
|
|
40
40
|
'account_not_found',
|
|
41
41
|
'admin_required',
|
|
42
|
+
'api_not_approved',
|
|
42
43
|
'cashregister_not_assigned',
|
|
43
44
|
'cashregister_not_found',
|
|
44
45
|
'cashregister_token_invalid',
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { VatRate } from '../enums/index.js';
|
|
2
|
+
import { type ReturnDisposition } from './cancellation.js';
|
|
2
3
|
/**
|
|
3
4
|
* Belegposition — Zwilling von `KasseneckItem` in
|
|
4
5
|
* kasseneck_api/lib/models/kasseneck_item.dart.
|
|
@@ -50,6 +51,10 @@ export interface ReceiptItem {
|
|
|
50
51
|
* im Bericht. Optional; Handeingaben haben keinen.
|
|
51
52
|
*/
|
|
52
53
|
articleId?: string;
|
|
54
|
+
/** Nur an Storno-Zeilen mit `articleId`: Index der Position im Original. */
|
|
55
|
+
originalIndex?: number;
|
|
56
|
+
/** Nur an Storno-Zeilen mit `articleId`: wohin die Ware ging (Lager-Kern Stufe 2). */
|
|
57
|
+
returnDisposition?: ReturnDisposition;
|
|
53
58
|
}
|
|
54
59
|
/** Empfaenger einer Trinkgeld-Position (Kassen-Benutzer, Snapshot des Namens). */
|
|
55
60
|
export interface TipRecipient {
|
|
@@ -117,6 +122,10 @@ export interface ReceiptItemPayloadRead {
|
|
|
117
122
|
vat?: number | null;
|
|
118
123
|
/** Artikel-Verweis, siehe [ReceiptItem.articleId]. */
|
|
119
124
|
articleId?: string | null;
|
|
125
|
+
/** Storno-Zeile mit `articleId`: Index im Original, siehe [ReceiptItem.originalIndex]. */
|
|
126
|
+
originalIndex?: number | null;
|
|
127
|
+
/** Storno-Zeile mit `articleId`: Rueckgabe-Wahl, siehe [ReceiptItem.returnDisposition]. */
|
|
128
|
+
returnDisposition?: string | null;
|
|
120
129
|
}
|
|
121
130
|
export declare function toReceiptItemPayload(item: ReceiptItem): ReceiptItemPayload;
|
|
122
131
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { VatRate } from '../enums/index.js';
|
|
2
2
|
import { readVatRateByRate, requireVatRateByRate } from './enum-payload.js';
|
|
3
|
+
import { isReturnDisposition } from './cancellation.js';
|
|
3
4
|
/** Trinkgeld-Position? Die eine Erkennungsstelle — niemand prueft `kind` selbst. */
|
|
4
5
|
export function isTipItem(item) {
|
|
5
6
|
return item != null && item.kind === 'tip';
|
|
@@ -80,6 +81,10 @@ export function fromReceiptItemPayload(payload) {
|
|
|
80
81
|
: {}),
|
|
81
82
|
// Artikel-Verweis erhalten (Storno-Spiegelung schreibt ihn wieder mit).
|
|
82
83
|
...(typeof payload.articleId === 'string' && payload.articleId !== '' ? { articleId: payload.articleId } : {}),
|
|
84
|
+
// Lager: Bezug und Rueckgabe-Wahl einer Storno-Zeile (nur gelesen; ein
|
|
85
|
+
// unbekannter Wert faellt weg wie am Rand des Servers).
|
|
86
|
+
...(Number.isInteger(payload.originalIndex) && payload.originalIndex >= 0 ? { originalIndex: payload.originalIndex } : {}),
|
|
87
|
+
...(isReturnDisposition(payload.returnDisposition) ? { returnDisposition: payload.returnDisposition } : {}),
|
|
83
88
|
};
|
|
84
89
|
}
|
|
85
90
|
/** Erster brauchbarer Zahlenwert der Reihe; `null`/`undefined`/NaN zaehlen nicht. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ReceiptType, KeckPaymentMethod, CreditCardProvider } from '../enums/index.js';
|
|
2
2
|
import { type ReceiptItem, type ReceiptItemPayload, type ReceiptItemPayloadRead } from './receipt-item.js';
|
|
3
3
|
import { type Voucher, type VoucherPayload } from './voucher.js';
|
|
4
|
-
import type
|
|
4
|
+
import { type Cancellation, type CancellationOf, type CancellationReason } from './cancellation.js';
|
|
5
5
|
import { type ZeroKind } from './receipt-summary.js';
|
|
6
6
|
import { type ReceiptPayment, type ReceiptPaymentPayload } from './receipt-payment.js';
|
|
7
7
|
/**
|
|
@@ -2,6 +2,7 @@ import { ReceiptType, KeckPaymentMethod, CreditCardProvider, VoucherAction, Vouc
|
|
|
2
2
|
import { readEnumKey, requireEnumKey } from './enum-payload.js';
|
|
3
3
|
import { toReceiptItemPayload, fromReceiptItemPayload, receiptItemTotalCents, } from './receipt-item.js';
|
|
4
4
|
import { toVoucherPayload, fromVoucherPayload } from './voucher.js';
|
|
5
|
+
import { isReturnDisposition } from './cancellation.js';
|
|
5
6
|
import { isZeroKind } from './receipt-summary.js';
|
|
6
7
|
import { fromReceiptPaymentPayload, toReceiptPaymentPayload } from './receipt-payment.js';
|
|
7
8
|
/**
|
|
@@ -100,7 +101,11 @@ function leseStorno(eintrag) {
|
|
|
100
101
|
at: Number(eintrag.at ?? 0),
|
|
101
102
|
by: eintrag.by ?? null,
|
|
102
103
|
note: eintrag.note ?? null,
|
|
103
|
-
items: (eintrag.items ?? []).map((p) => ({
|
|
104
|
+
items: (eintrag.items ?? []).map((p) => ({
|
|
105
|
+
index: Number(p.index),
|
|
106
|
+
quantity: Number(p.quantity),
|
|
107
|
+
...(isReturnDisposition(p.returnDisposition) ? { returnDisposition: p.returnDisposition } : {}),
|
|
108
|
+
})),
|
|
104
109
|
...(eintrag.promoAdjustmentCents && typeof eintrag.promoAdjustmentCents === 'object'
|
|
105
110
|
? { promoAdjustmentCents: Object.fromEntries(Object.entries(eintrag.promoAdjustmentCents).map(([k, v]) => [k, Number(v)])) }
|
|
106
111
|
: {}),
|
|
@@ -64,6 +64,14 @@ export interface PosArticle {
|
|
|
64
64
|
askQuantity: boolean | null;
|
|
65
65
|
/** Hoechstmenge je Beleg (bei kg/l/m auch Kommazahl); null = keine Grenze. */
|
|
66
66
|
maxQuantity: number | null;
|
|
67
|
+
/**
|
|
68
|
+
* Standorte, an denen der Artikel gefuehrt wird (Lager-Kern Stufe 2, innen
|
|
69
|
+
* `standorte`); `null`, wenn der Artikel keine Angabe traegt. Wie die Kasse
|
|
70
|
+
* daraus Kacheln filtert, entscheidet die Oberflaeche. Optional, damit
|
|
71
|
+
* bestehende Literale von Verbrauchern weiter uebersetzen; der Leser
|
|
72
|
+
* (`fromPosArticlePayload`) setzt das Feld immer (`null` oder Liste).
|
|
73
|
+
*/
|
|
74
|
+
stockLocationIds?: string[] | null;
|
|
67
75
|
}
|
|
68
76
|
/** Deckelt eine gewuenschte Menge an der Hoechstmenge des Artikels (null = keine Grenze). */
|
|
69
77
|
export declare function allowedQuantity(a: Pick<PosArticle, 'maxQuantity'>, wanted: number): number;
|
|
@@ -84,7 +92,13 @@ export interface PosArticlePayload {
|
|
|
84
92
|
quantityRule?: string | null;
|
|
85
93
|
askQuantity?: boolean | null;
|
|
86
94
|
maxQuantity?: number | null;
|
|
95
|
+
stockLocationIds?: string[] | null;
|
|
87
96
|
}
|
|
88
97
|
export declare function fromPosArticlePayload(p: PosArticlePayload): PosArticle;
|
|
98
|
+
/**
|
|
99
|
+
* Die Liste `data.<feld>` einer Antwort, jedes Element durch `lesen` (mit
|
|
100
|
+
* seinem Index fuer Fehlermeldungen). Paketintern: auch `lager.ts` liest so.
|
|
101
|
+
*/
|
|
102
|
+
export declare function liste<T>(daten: unknown, feld: string, name: string, lesen: (e: unknown, index: number) => T): T[];
|
|
89
103
|
export declare function listMyArticleGroups(transport: InternerTransport): Promise<ArticleGroup[]>;
|
|
90
104
|
export declare function listMyArticles(transport: InternerTransport): Promise<PosArticle[]>;
|
package/dist/esm/pos/artikel.js
CHANGED
|
@@ -60,14 +60,24 @@ export function fromPosArticlePayload(p) {
|
|
|
60
60
|
quantityRule: p.quantityRule === 'piece' || p.quantityRule === 'decimal' ? p.quantityRule : null,
|
|
61
61
|
askQuantity: typeof p.askQuantity === 'boolean' ? p.askQuantity : null,
|
|
62
62
|
maxQuantity: typeof p.maxQuantity === 'number' && Number.isFinite(p.maxQuantity) && p.maxQuantity > 0 ? p.maxQuantity : null,
|
|
63
|
+
stockLocationIds: Array.isArray(p.stockLocationIds)
|
|
64
|
+
? p.stockLocationIds.filter((s) => typeof s === 'string' && s !== '')
|
|
65
|
+
: null,
|
|
63
66
|
};
|
|
64
67
|
}
|
|
65
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Die Liste `data.<feld>` einer Antwort, jedes Element durch `lesen` (mit
|
|
70
|
+
* seinem Index fuer Fehlermeldungen). Paketintern: auch `lager.ts` liest so.
|
|
71
|
+
*/
|
|
72
|
+
export function liste(daten, feld, name, lesen) {
|
|
66
73
|
const roh = daten?.[feld];
|
|
67
74
|
if (!Array.isArray(roh)) {
|
|
68
|
-
|
|
75
|
+
const grund = roh === undefined || roh === null
|
|
76
|
+
? `Antwort enthaelt keine Liste (data.${feld} fehlt)`
|
|
77
|
+
: `Antwort ist unbrauchbar (data.${feld} ist keine Liste)`;
|
|
78
|
+
throw new KasseneckValidationError(name, grund, 'response');
|
|
69
79
|
}
|
|
70
|
-
return roh.map((e) => lesen(typeof e === 'object' && e !== null ? e : {}));
|
|
80
|
+
return roh.map((e, i) => lesen(typeof e === 'object' && e !== null ? e : {}, i));
|
|
71
81
|
}
|
|
72
82
|
export async function listMyArticleGroups(transport) {
|
|
73
83
|
const daten = await transport('listMyArticleGroups');
|
package/dist/esm/pos/errors.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { KasseneckApiError } from '../client/errors.js';
|
|
2
2
|
/**
|
|
3
3
|
* Fehler der Kassen-Aufrufe um den Verkauf herum (Einstellungen, Logo,
|
|
4
|
-
* Artikel, Drucker, Trinkgeld-Empfaenger) auswerten: am `code`, nie am Text.
|
|
4
|
+
* Artikel, Drucker, Trinkgeld-Empfaenger, Lager) auswerten: am `code`, nie am Text.
|
|
5
5
|
* Belege, Storno und Belegmail haben eigene Listen (`RECEIPT_ERROR_CODES`,
|
|
6
6
|
* `CANCELLATION_ERROR_CODES`, `RECEIPT_EMAIL_ERROR_CODES`), die Anmeldung
|
|
7
7
|
* `REGISTER_ERROR_CODES` im Unterpfad `./register`.
|
|
8
8
|
*
|
|
9
|
-
* Abgeleitet aus dem Vertrags-Export (Fehlerfaelle dieser
|
|
9
|
+
* Abgeleitet aus dem Vertrags-Export (Fehlerfaelle dieser dreizehn Endpunkte in
|
|
10
10
|
* `fixtures/v3/antworten/kasse.json` und ihre Handler-Codes); ein Test haelt
|
|
11
11
|
* die Liste deckungsgleich. `validation` traegt `data.errors[]` mit dem
|
|
12
12
|
* aeusseren Feldpfad (`business.theme`, `device.shortcuts.splitPayment`).
|
|
@@ -19,7 +19,7 @@ import { KasseneckApiError } from '../client/errors.js';
|
|
|
19
19
|
* ueber `KasseneckApiError.code` lesbar; die Kasse braucht dafuer einen
|
|
20
20
|
* Rueckfallzweig.
|
|
21
21
|
*/
|
|
22
|
-
export declare const POS_ERROR_CODES: readonly ["account_not_found", "admin_required", "cashregister_not_assigned", "cashregister_not_found", "cashregister_token_invalid", "cashregister_token_missing", "device_not_found", "dialect_mismatch", "internal_translation_error", "live_not_enabled", "logo_invalid", "logo_invalid_type", "logo_too_large", "method_not_allowed", "mfa_required", "module_inactive", "not_found", "not_permitted", "print_job_not_found", "print_layout_failed", "printer_not_found", "register_user_no_business", "register_user_not_allowed", "register_user_not_found", "response_translation_failed", "session_expired", "session_other_cashregister", "unauthorized", "user_disabled", "user_verification_failed", "validation", "route_missing"];
|
|
22
|
+
export declare const POS_ERROR_CODES: readonly ["account_not_found", "admin_required", "api_not_approved", "cashregister_not_assigned", "cashregister_not_found", "cashregister_token_invalid", "cashregister_token_missing", "device_not_found", "dialect_mismatch", "internal_translation_error", "live_not_enabled", "location_inactive", "location_not_found", "logo_invalid", "logo_invalid_type", "logo_too_large", "method_not_allowed", "mfa_required", "module_inactive", "not_found", "not_permitted", "print_job_not_found", "print_layout_failed", "printer_not_found", "register_user_no_business", "register_user_not_allowed", "register_user_not_found", "response_translation_failed", "server_error", "session_expired", "session_other_cashregister", "unauthorized", "user_disabled", "user_verification_failed", "validation", "route_missing"];
|
|
23
23
|
export type PosErrorCode = typeof POS_ERROR_CODES[number];
|
|
24
24
|
export declare function isPosErrorCode(value: unknown): value is PosErrorCode;
|
|
25
25
|
/** Der Code eines geworfenen Fehlers, wenn er in [POS_ERROR_CODES] steht; sonst `undefined`. */
|
package/dist/esm/pos/errors.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { KasseneckApiError } from '../client/errors.js';
|
|
2
2
|
/**
|
|
3
3
|
* Fehler der Kassen-Aufrufe um den Verkauf herum (Einstellungen, Logo,
|
|
4
|
-
* Artikel, Drucker, Trinkgeld-Empfaenger) auswerten: am `code`, nie am Text.
|
|
4
|
+
* Artikel, Drucker, Trinkgeld-Empfaenger, Lager) auswerten: am `code`, nie am Text.
|
|
5
5
|
* Belege, Storno und Belegmail haben eigene Listen (`RECEIPT_ERROR_CODES`,
|
|
6
6
|
* `CANCELLATION_ERROR_CODES`, `RECEIPT_EMAIL_ERROR_CODES`), die Anmeldung
|
|
7
7
|
* `REGISTER_ERROR_CODES` im Unterpfad `./register`.
|
|
8
8
|
*
|
|
9
|
-
* Abgeleitet aus dem Vertrags-Export (Fehlerfaelle dieser
|
|
9
|
+
* Abgeleitet aus dem Vertrags-Export (Fehlerfaelle dieser dreizehn Endpunkte in
|
|
10
10
|
* `fixtures/v3/antworten/kasse.json` und ihre Handler-Codes); ein Test haelt
|
|
11
11
|
* die Liste deckungsgleich. `validation` traegt `data.errors[]` mit dem
|
|
12
12
|
* aeusseren Feldpfad (`business.theme`, `device.shortcuts.splitPayment`).
|
|
@@ -22,6 +22,7 @@ import { KasseneckApiError } from '../client/errors.js';
|
|
|
22
22
|
export const POS_ERROR_CODES = Object.freeze([
|
|
23
23
|
'account_not_found',
|
|
24
24
|
'admin_required',
|
|
25
|
+
'api_not_approved',
|
|
25
26
|
'cashregister_not_assigned',
|
|
26
27
|
'cashregister_not_found',
|
|
27
28
|
'cashregister_token_invalid',
|
|
@@ -30,6 +31,8 @@ export const POS_ERROR_CODES = Object.freeze([
|
|
|
30
31
|
'dialect_mismatch',
|
|
31
32
|
'internal_translation_error',
|
|
32
33
|
'live_not_enabled',
|
|
34
|
+
'location_inactive',
|
|
35
|
+
'location_not_found',
|
|
33
36
|
'logo_invalid',
|
|
34
37
|
'logo_invalid_type',
|
|
35
38
|
'logo_too_large',
|
|
@@ -45,6 +48,7 @@ export const POS_ERROR_CODES = Object.freeze([
|
|
|
45
48
|
'register_user_not_allowed',
|
|
46
49
|
'register_user_not_found',
|
|
47
50
|
'response_translation_failed',
|
|
51
|
+
'server_error',
|
|
48
52
|
'session_expired',
|
|
49
53
|
'session_other_cashregister',
|
|
50
54
|
'unauthorized',
|
package/dist/esm/pos/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Kachel-Kasse: Einstellungen, Artikelgruppen/Artikel fuer Kacheln,
|
|
3
|
-
* Rabattverteilung, Drucker, Trinkgeld-Empfaenger
|
|
3
|
+
* Rabattverteilung, Drucker, Trinkgeld-Empfaenger, Lager (Standorte, Bestand,
|
|
4
|
+
* Standort der Kasse). Die Aufrufe heissen 1:1 wie
|
|
4
5
|
* die Backend-Functions (die Rewrites-Waechter der Web-App leiten daraus ab)
|
|
5
6
|
* und sprechen den Kassenweg `/api/v3` (Schluessel und Werte englisch).
|
|
6
7
|
*/
|
|
@@ -9,7 +10,9 @@ export { type ArticleGroup, type ArticleGroupPayload, fromArticleGroupPayload, t
|
|
|
9
10
|
export { getPosSettings, setMyPosSettings, setMyRegisterDeviceSettings, setMyPosLogo, posSettingsFromWire, type SetMyPosLogoOptions, } from './client.js';
|
|
10
11
|
export { POS_ERROR_CODES, type PosErrorCode, isPosErrorCode, posErrorCode, isPosError, type PosFieldError, posFieldErrors, } from './errors.js';
|
|
11
12
|
export { distributeDiscount } from '../receipt/discount.js';
|
|
12
|
-
export { cancelScopeOf, receiptsScopeOf, type RegisterScope, type RegisterUserPerms } from '../register/pairing.js';
|
|
13
|
+
export { cancelScopeOf, receiptsScopeOf, stockViewOf, type RegisterScope, type RegisterUserPerms } from '../register/pairing.js';
|
|
13
14
|
export { type NetworkPrinter, type PrintJob, type PrintJobStatus, PRINT_JOB_STATUSES, type PrintJobSource, PRINT_JOB_SOURCES, isPrintJobFinished, type CreatePrintJobOptions, listMyPrinters, createPrintJob, getPrintJob, } from './drucker.js';
|
|
14
15
|
export { listMyTipRecipients } from './trinkgeld.js';
|
|
16
|
+
export { STOCK_LOCATION_TYPES, type StockLocationType, type StockLocation, type StockLocationAddress, type StockLevel, type StockValue, type StockList, type ListMyStockOptions, type SetMyCashregisterStockLocationOptions, type CashregisterStockLocation, listMyStockLocations, listMyStock, setMyCashregisterStockLocation, } from './lager.js';
|
|
17
|
+
export { RETURN_DISPOSITIONS, isReturnDisposition, type ReturnDisposition } from '../models/cancellation.js';
|
|
15
18
|
export { MESSAGES, ERROR_RULES, ERROR_CODE_RULES, ERROR_OUTCOME_RULES, CALLS_WITH_EFFECT, findErrorRule, messageOutcome, messageText, messageAppliesTo, RECEIPT_EMAIL_ERROR_MESSAGES, receiptEmailErrorMessage, CANCELLATION_PAYMENT_ERROR_MESSAGES, cancellationPaymentErrorMessage, LABELS, labelText, type TextEntry, type MessageKey, type ErrorKind, type ErrorRule, type ErrorRuleDetail, type Surface, type ReceiptEmailMessageCode, type CancellationPaymentMessageCode, type LabelKey, } from './texte.js';
|
package/dist/esm/pos/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Kachel-Kasse: Einstellungen, Artikelgruppen/Artikel fuer Kacheln,
|
|
3
|
-
* Rabattverteilung, Drucker, Trinkgeld-Empfaenger
|
|
3
|
+
* Rabattverteilung, Drucker, Trinkgeld-Empfaenger, Lager (Standorte, Bestand,
|
|
4
|
+
* Standort der Kasse). Die Aufrufe heissen 1:1 wie
|
|
4
5
|
* die Backend-Functions (die Rewrites-Waechter der Web-App leiten daraus ab)
|
|
5
6
|
* und sprechen den Kassenweg `/api/v3` (Schluessel und Werte englisch).
|
|
6
7
|
*/
|
|
@@ -13,8 +14,11 @@ export { POS_ERROR_CODES, isPosErrorCode, posErrorCode, isPosError, posFieldErro
|
|
|
13
14
|
export { distributeDiscount } from '../receipt/discount.js';
|
|
14
15
|
// Reichweiten der Kassen-Rechte (Migration wie im Backend) -- bewusst NICHT im
|
|
15
16
|
// Register-Unterpfad: dessen Exportnamen sind 1:1 Function-Namen (Rewrites).
|
|
16
|
-
export { cancelScopeOf, receiptsScopeOf } from '../register/pairing.js';
|
|
17
|
+
export { cancelScopeOf, receiptsScopeOf, stockViewOf } from '../register/pairing.js';
|
|
17
18
|
export { PRINT_JOB_STATUSES, PRINT_JOB_SOURCES, isPrintJobFinished, listMyPrinters, createPrintJob, getPrintJob, } from './drucker.js';
|
|
18
19
|
export { listMyTipRecipients } from './trinkgeld.js';
|
|
20
|
+
export { STOCK_LOCATION_TYPES, listMyStockLocations, listMyStock, setMyCashregisterStockLocation, } from './lager.js';
|
|
21
|
+
// Rueckgabe-Wahl beim Storno (Kassen-Dialog); dieselbe Liste wie an der Wurzel.
|
|
22
|
+
export { RETURN_DISPOSITIONS, isReturnDisposition } from '../models/cancellation.js';
|
|
19
23
|
// Was die Kasse selbst sagt: ein Katalog fuer Browser-Kasse und App.
|
|
20
24
|
export { MESSAGES, ERROR_RULES, ERROR_CODE_RULES, ERROR_OUTCOME_RULES, CALLS_WITH_EFFECT, findErrorRule, messageOutcome, messageText, messageAppliesTo, RECEIPT_EMAIL_ERROR_MESSAGES, receiptEmailErrorMessage, CANCELLATION_PAYMENT_ERROR_MESSAGES, cancellationPaymentErrorMessage, LABELS, labelText, } from './texte.js';
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { InternerTransport } from '../client/aufrufe.js';
|
|
2
|
+
/**
|
|
3
|
+
* Lager an der Kasse (Lager-Kern Stufe 2, Backend lager-endpoints.js):
|
|
4
|
+
* Standorte, Bestand und der Standort der Kasse. Alle drei Aufrufe gibt es
|
|
5
|
+
* nur ueber den Kassenweg `/api/v3` (registerInternal); Rechte am Server:
|
|
6
|
+
* `stockView` (lesen), `stockCosts` (Werte), `stockLocation` (Standort setzen).
|
|
7
|
+
*
|
|
8
|
+
* **Ganzzahlen:** Mengen sind Tausendstel der Basiseinheit (`1000` = 1 Stueck,
|
|
9
|
+
* `250` = 0,250 kg), Werte ganze Cent bzw. Mikro-Euro. Nichts wird geteilt,
|
|
10
|
+
* gerundet oder geklemmt -- ein negativer Bestand (mehr verkauft als gebucht)
|
|
11
|
+
* ist eine Aussage des Servers und bleibt negativ. Eine Zahl, die keine
|
|
12
|
+
* Ganzzahl ist, oder eine fehlende Menge wird **nie** zu `0`: der Aufruf
|
|
13
|
+
* endet mit `KasseneckValidationError` (`scope: 'response'`), denn „kein
|
|
14
|
+
* Bestand“ und „Antwort kaputt“ sind verschiedene Aussagen.
|
|
15
|
+
*/
|
|
16
|
+
/** Standort-Typen (Katalog `STANDORT_TYP`), englisch wie am Draht. */
|
|
17
|
+
export declare const STOCK_LOCATION_TYPES: readonly ["warehouse", "store", "vehicle", "other"];
|
|
18
|
+
export type StockLocationType = (typeof STOCK_LOCATION_TYPES)[number];
|
|
19
|
+
export interface StockLocationAddress {
|
|
20
|
+
street: string | null;
|
|
21
|
+
zip: string | null;
|
|
22
|
+
city: string | null;
|
|
23
|
+
country: string | null;
|
|
24
|
+
}
|
|
25
|
+
export interface StockLocation {
|
|
26
|
+
id: string;
|
|
27
|
+
name: string;
|
|
28
|
+
/** `null`: ein Typ, den dieses Paket nicht kennt. */
|
|
29
|
+
type: StockLocationType | null;
|
|
30
|
+
/** Fahrzeuge haben keine Adresse. */
|
|
31
|
+
address: StockLocationAddress | null;
|
|
32
|
+
/** Kennzeichen, nur bei `vehicle`. */
|
|
33
|
+
licensePlate: string | null;
|
|
34
|
+
/** `false` = aufgeloest; als Standort der Kasse abgewiesen (`location_inactive`). */
|
|
35
|
+
active: boolean;
|
|
36
|
+
/** `true` = Hauptstandort, den der Server ohne eigenes Dokument ergaenzt. */
|
|
37
|
+
virtual: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** Bestand eines Artikels an einem Standort, in Tausendstel der Basiseinheit. */
|
|
40
|
+
export interface StockLevel {
|
|
41
|
+
articleId: string;
|
|
42
|
+
locationId: string;
|
|
43
|
+
sellable: number;
|
|
44
|
+
defective: number;
|
|
45
|
+
reserved: number;
|
|
46
|
+
/** `sellable - reserved`, vom Server gerechnet. */
|
|
47
|
+
available: number;
|
|
48
|
+
}
|
|
49
|
+
/** Lagerwert eines Artikels -- nur mit dem Recht `stockCosts`. */
|
|
50
|
+
export interface StockValue {
|
|
51
|
+
articleId: string;
|
|
52
|
+
stockValueCents: number;
|
|
53
|
+
/** Durchschnittlicher Einstandspreis je Basiseinheit in Mikro-Euro; `null` bei Menge 0. */
|
|
54
|
+
averageCostMicros: number | null;
|
|
55
|
+
}
|
|
56
|
+
export interface StockList {
|
|
57
|
+
stock: StockLevel[];
|
|
58
|
+
/**
|
|
59
|
+
* `null`, wenn der Aufrufer das Recht `stockCosts` nicht hat (der Server
|
|
60
|
+
* laesst das Feld weg); `[]`, wenn er es hat und nichts bewertet ist. Eine
|
|
61
|
+
* Oberflaeche zeigt bei `null` keinen Wert, nie „0,00 €“.
|
|
62
|
+
*/
|
|
63
|
+
values: StockValue[] | null;
|
|
64
|
+
}
|
|
65
|
+
export interface ListMyStockOptions {
|
|
66
|
+
/** Nur dieser Standort; `''` gilt wie nicht angegeben. */
|
|
67
|
+
locationId?: string;
|
|
68
|
+
/** Nur dieser Artikel; `''` gilt wie nicht angegeben. */
|
|
69
|
+
articleId?: string;
|
|
70
|
+
/** Nur Zeilen unter dem Mindestbestand. */
|
|
71
|
+
belowMinimum?: boolean;
|
|
72
|
+
}
|
|
73
|
+
export interface SetMyCashregisterStockLocationOptions {
|
|
74
|
+
/** Standort-Kennung; `null` setzt auf den Standard-Standort des Betriebs zurueck. */
|
|
75
|
+
stockLocationId: string | null;
|
|
76
|
+
/** Ohne Angabe gilt die Kasse der Anmeldung (`registerUserAuth`). */
|
|
77
|
+
cashregisterId?: string;
|
|
78
|
+
}
|
|
79
|
+
export interface CashregisterStockLocation {
|
|
80
|
+
cashregisterId: string;
|
|
81
|
+
/** `null` = Standard-Standort des Betriebs. */
|
|
82
|
+
stockLocationId: string | null;
|
|
83
|
+
}
|
|
84
|
+
/** Standorte des Betriebs, samt aufgeloesten (`active: false`) und dem Hauptstandort. */
|
|
85
|
+
export declare function listMyStockLocations(transport: InternerTransport): Promise<StockLocation[]>;
|
|
86
|
+
/** Bestand je Artikel und Standort; Werte nur mit dem Recht `stockCosts`. */
|
|
87
|
+
export declare function listMyStock(transport: InternerTransport, options?: ListMyStockOptions): Promise<StockList>;
|
|
88
|
+
/**
|
|
89
|
+
* Standort der Kasse setzen -- von dort bucht der Server Verkauf und Storno
|
|
90
|
+
* ab. `stockLocationId: null` setzt zurueck (am Draht der leere Text).
|
|
91
|
+
* Fehler am Code: `location_not_found`, `location_inactive`,
|
|
92
|
+
* `cashregister_not_found`, `cashregister_not_assigned`, `not_permitted`,
|
|
93
|
+
* `module_inactive`.
|
|
94
|
+
*/
|
|
95
|
+
export declare function setMyCashregisterStockLocation(transport: InternerTransport, options: SetMyCashregisterStockLocationOptions): Promise<CashregisterStockLocation>;
|
|
@@ -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
|
+
}
|
|
@@ -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) {
|