@kreiseck/kasseneck-api 0.27.2 → 0.28.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/README.md +59 -9
  3. package/dist/cjs/partner/ablauf.d.ts +4 -3
  4. package/dist/cjs/partner/ablauf.js +4 -3
  5. package/dist/cjs/partner/api.d.ts +20 -8
  6. package/dist/cjs/partner/api.js +12 -1
  7. package/dist/cjs/partner/endpunkte.d.ts +9 -12
  8. package/dist/cjs/partner/endpunkte.js +85 -26
  9. package/dist/cjs/partner/fehler.d.ts +1 -1
  10. package/dist/cjs/partner/fehler.js +8 -3
  11. package/dist/cjs/partner/index.d.ts +7 -3
  12. package/dist/cjs/partner/index.js +7 -2
  13. package/dist/cjs/partner/typen.d.ts +144 -34
  14. package/dist/cjs/partner/typen.js +4 -0
  15. package/dist/cjs/partner/webhooks.d.ts +76 -14
  16. package/dist/cjs/partner/webhooks.js +40 -12
  17. package/dist/cjs/payments/index.d.ts +5 -4
  18. package/dist/cjs/payments/index.js +4 -3
  19. package/dist/cjs/rechnung/summen.d.ts +18 -3
  20. package/dist/cjs/rechnung/summen.js +18 -3
  21. package/dist/cjs/rechnung/typen.d.ts +1 -1
  22. package/dist/cjs/rechnung/vertrag.d.ts +1 -1
  23. package/dist/cjs/rechnung/vertrag.js +1 -1
  24. package/dist/esm/partner/ablauf.d.ts +4 -3
  25. package/dist/esm/partner/ablauf.js +4 -3
  26. package/dist/esm/partner/api.d.ts +20 -8
  27. package/dist/esm/partner/api.js +11 -1
  28. package/dist/esm/partner/endpunkte.d.ts +9 -12
  29. package/dist/esm/partner/endpunkte.js +85 -26
  30. package/dist/esm/partner/fehler.d.ts +1 -1
  31. package/dist/esm/partner/fehler.js +8 -3
  32. package/dist/esm/partner/index.d.ts +7 -3
  33. package/dist/esm/partner/index.js +5 -1
  34. package/dist/esm/partner/typen.d.ts +144 -34
  35. package/dist/esm/partner/typen.js +4 -0
  36. package/dist/esm/partner/webhooks.d.ts +76 -14
  37. package/dist/esm/partner/webhooks.js +40 -12
  38. package/dist/esm/payments/index.d.ts +5 -4
  39. package/dist/esm/payments/index.js +4 -3
  40. package/dist/esm/rechnung/summen.d.ts +18 -3
  41. package/dist/esm/rechnung/summen.js +18 -3
  42. package/dist/esm/rechnung/typen.d.ts +1 -1
  43. package/dist/esm/rechnung/vertrag.d.ts +1 -1
  44. package/dist/esm/rechnung/vertrag.js +1 -1
  45. package/fixtures/hobex-hps-codes.json +1 -1
  46. package/fixtures/kasse-texte.json +1 -1
  47. package/fixtures/oberflaeche.json +3 -1
  48. package/fixtures/rechnung-api.schema.json +1 -1
  49. package/fixtures/rechnung-texte.json +1 -1
  50. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,83 @@ Was vor 0.7.0 geschah, steht in der Commit-Historie (`git log`); ab hier wird
4
4
  es hier geführt. Ein Eintrag nennt die Änderung **und ihren Grund** —
5
5
  nur der Grund überlebt den nächsten Umbau.
6
6
 
7
+ ## 0.28.0
8
+
9
+ - **Bricht `./partner` (und nur das): der Partner-Teil spricht jetzt die englische Partner-API
10
+ `/v3`.** Vorgabe-Adresse ist `PARTNER_BASE_URL` (`https://api.kasseneck.at/v3`), `baseUrl` bleibt
11
+ einstellbar. Grund: das Backend führt die Partner-API ab `/v3` durchgehend englisch (Feldnamen
12
+ und jeder Wert, auf den ein Programm verzweigt), `/v1` ist abgekündigt (Kopfzeilen `Deprecation`
13
+ und `Sunset`). `/v3` weist die deutschen Werte der `/v1` mit `validation` ab statt sie still zu
14
+ übersetzen; ein Client, der weiter `einzel` oder `wien` schickt, bekäme nur noch Fehler.
15
+ Minor-Sprung, weil 0.x: wer `./partner` benutzt, muss umstellen, alles andere nicht.
16
+ - Umbenannte Werte (alt → neu): `legalForm` `einzel`/`verein`/`sonstige` →
17
+ `sole_proprietor`/`association`/`other`; `state` `burgenland` … `wien` → `AT-1` … `AT-9`;
18
+ Kontaktrollen `geschaeftsfuehrung`/`buchhaltung`/`technik`/`kasse` →
19
+ `management`/`accounting`/`technical`/`pos`; `avv.mode` `direkt`/`vollmacht`/`unterauftrag` →
20
+ `direct`/`power_of_attorney`/`subprocessor`; Entgelt `entgelt {cents, rhythmus, test}` →
21
+ `fee {cents, interval, test}` mit `monthly`/`yearly`/`once` (neu gelesen an
22
+ `createPartnerCustomer` und `requestCustomerSignature`); Historiengründe
23
+ `karte_eingetragen`/`fon` → `card_entered`/`finanzonline`; Zustellstatus
24
+ `zugestellt`/`offen`/`fehlgeschlagen`/`verworfen` → `delivered`/`pending`/`failed`/`dropped`;
25
+ `deletePartnerWebhook` liefert `{ webhookId, deleted }` statt nur der Kennung; Ereignisse
26
+ `customer.terms_accepted`/`customer.avv_accepted` mit `kind` `terms`/`avv` und den englischen
27
+ Quellen (`setup_link`, `process_link`, `partner_power_of_attorney`, `admin_paper`,
28
+ `paper_upload`), beschrieben durch den neuen Typ `ContractAcceptedEventData`.
29
+ - Neue englische Typen `LegalForm`, `AustrianState`, `ContactRole`, `AvvMode`, `FeeInterval`,
30
+ `PartnerFee`, `SignatureHistoryReason`, `WebhookApiVersion`, `WebhookDeliveryStatus`;
31
+ `Rechtsform`, `Bundesland` und `KontaktRolle` bleiben als veraltete Aliase.
32
+ - **Webhooks tragen `apiVersion`** (`v1` oder `v3`; fehlt es, ist es ein Bestands-Webhook und damit
33
+ `v1`). Die Sprache der Nutzlast folgt dem Webhook, nicht dem Pfad: ein unter `/v1` angelegter
34
+ schickt weiter deutsch, bis er mit `updatePartnerWebhook(id, { apiVersion: 'v3' })` umgestellt
35
+ wird; zurück gibt es nicht. `lastDelivery` ist jetzt das Objekt `{ at, status, statusCode }`,
36
+ das der Server schon immer schickte (der Typ sagte `number`).
37
+ - Dabei berichtigt, was schon unter `/v1` englisch war und hier noch deutsch gelesen wurde (und
38
+ darum leer blieb): `getCustomerSignatureStatus` liest `signature` statt `signatur` und neu
39
+ `signatures[]` und `customerId`; ein Antrag trägt `kind` statt `art`, die Historie `from`/`to`
40
+ statt `von`/`nach`; `requestCustomerSignature` sendet `kind` statt `art`;
41
+ `sendPartnerWebhookTest` liest `event` statt `ereignis`; Zustellungen tragen
42
+ `lastAttemptAt`/`nextAttemptAt`; `BetriebSteuer.uid` heißt `vatId` (ein `uid` wies der Server
43
+ als unbekanntes Feld ab); Kassenschritt `signature` statt `signatur`, Kassenstatus
44
+ `in_progress` statt `laeuft`.
45
+ - **`PARTNER_FEHLER_CODES` um `kennung_fehlt` und `vertrag_offen` ergänzt**, beide mit
46
+ Handlungssatz. Grund: der Katalog des Backends (`partner-core.FEHLER_KATALOG`, Fläche `beide`)
47
+ führt sie für die Schnittstelle; `kennung_fehlt` kommt aus `sendPartnerCustomerFonLink`,
48
+ `vertrag_offen` live aus `activateCashregister`. Ein Code, den das Paket nicht kennt, sah für
49
+ einen Aufrufer aus wie „gibt es nicht“.
50
+ - **Liste und Einzelsicht eines Betriebs führen `fon`, `avv` und `terms`** in der Form, die der
51
+ Server schickt (`VertragStand`, `KundenFonStand`; die Einzelsicht zusätzlich `verifiedAt` und
52
+ `linkSentTo`). Fehlen sie in der Antwort, bleibt es bei `null`. Der Kommentar an `AvvStand`
53
+ behauptete, Verträge wirkten im Partner-Weg nicht mehr; tatsächlich geht live ohne AVV und
54
+ Nutzungsvertrag keine Kasse live (`vertrag_offen`). Berichtigt, ebenso in `ablauf.ts`.
55
+ - `check:erreichbar` prüft die Partner-Aufrufe unter `/v3` (abgelesen aus der Partner-Fassade des
56
+ Baus), alles andere weiter unter `/v1`. Ein `not_found` aus JSON gilt nicht mehr als erreichbar:
57
+ unter `/v3` antwortet der Rand auf einen nicht gerouteten Namen selbst mit JSON.
58
+ - **Unverändert:** Belege, Rechnungen, Kasse, Druck, Zahlungen und React sprechen weiter `/v1`
59
+ (`DEFAULT_BASE_URL`), bis es dort eine `/v3` gibt. Die Fehlercodes bleiben in dieser Stufe wie
60
+ in `/v1`, ebenso die Prüfung der Webhook-Signatur. `reportCustomerVertrag` (unter `/v3`
61
+ `reportCustomerContract`) führt dieses Paket nicht und bekommt es auch jetzt nicht.
62
+ - Die Tests lesen echte `/v3`-Antworten: `test/fixtures/partner-v3-antworten.json` entsteht aus
63
+ den Sichten des Backends, durch dessen `/v3`-Rand gereicht (`scripts/partner-v3-antworten.cjs`).
64
+
65
+ ## 0.27.3
66
+
67
+ - **`rechnungSummen` ist als veraltet markiert** (`@deprecated`), das Rechenergebnis bleibt
68
+ unverändert. Grund: seit dem 23.09.2026, 17:05 Uhr stellt der Server jede neue Rechnung über den
69
+ exakten Kern (`rechnungRechnen`) aus; `rechnungSummen` rechnet nach Weg 2 und liegt an
70
+ Halbcent-Grenzen einen Cent je Satz daneben (21,35 € netto zu 10 %: 23,48 € statt 23,49 €). Auf
71
+ den Kern umgestellt wird bewusst nicht: der Server schaltet ihn je Konto über `ganzzahlPflicht`,
72
+ Entwürfe außerhalb des Ausstellens rechnet er teils weiter nach Weg 2, und
73
+ `fixtures/rechnung-summen.json` prüfen Backend und Dart-Zwilling. Der Kopfkommentar behauptete
74
+ noch, die Funktion rechne „genau so wie der Server“; das ist berichtigt, README ebenso.
75
+ - **`HpsRefundOptions`, `HpsCancelOptions`, `HpsConnectRefundOptions` und
76
+ `HpsConnectCancelOptions` werden unter `…/payments` exportiert** (nur hinzugefügt). Die Aufrufe
77
+ `refund`/`cancel` gab es dort schon, ihre Optionstypen nicht. Der Kopfkommentar von
78
+ `src/payments/index.ts` sagte noch, Gutschrift und Storno gingen nur über die Flutter-App; das
79
+ gilt seit Connect `/v1/terminal/refund` bzw. `/cancel` nicht mehr.
80
+ - § 131b Abs. 1 Z 3 steht in der **BAO**, nicht im UStG: an `INVOICE_PAYMENT_METHODS` und
81
+ `PaymentInput.onSite` berichtigt (Wortlaut gegen das RIS geprüft). Ein Test hält künftig jede
82
+ Zuordnung von § 131 ff. zum UStG in `src/` fest.
83
+
7
84
  ## 0.27.2
8
85
 
9
86
  - **README auf Englisch** und jede Angabe gegen den Code geprüft. Anfragen kommen inzwischen auch
package/README.md CHANGED
@@ -167,7 +167,7 @@ adapter:
167
167
  | `…/payments` | Stripe payment links, Hobex cloud (both HTTP endpoints of the backend), and Hobex **HPS** via **Kasseneck Connect** (local device agent that talks to the terminal). |
168
168
  | `…/register` | Sign-in for the browser register: pair and unpair a device, list its users and sessions, sign in by PIN, renew and end the session. |
169
169
  | `…/kasse` | Tile register: register settings (business-wide and per device), article groups and articles for tiles, discount distribution per VAT rate, scopes of register permissions, network printers and print jobs, tip recipients, the register's message catalogue. |
170
- | `…/partner` | Partner API: create businesses, FinanzOnline link, signature, cash registers, credentials, webhooks with signature verification. **Belongs on a server.** |
170
+ | `…/partner` | Partner API (`/v3`, English): create businesses, FinanzOnline link, signature, cash registers, credentials, webhooks with signature verification. **Belongs on a server.** |
171
171
  | `…/rechnung` | Invoice API: create and search customers, issue finalised invoices, credit notes and cancellation, PDF and e-invoice XML, the contract as data. **Belongs on a server.** |
172
172
  | `…/rechnung/rechnen` | Pure calculation core for invoice totals (integers, no transport, no dependency beyond types). Safe to run in the browser. |
173
173
  | `…/react` | Thin React adapter that renders a receipt layout or a receipt sheet. Needs React. |
@@ -537,6 +537,14 @@ receipts on their behalf.
537
537
  The partner key (`pk_live_…`) belongs on a **server**. It can create
538
538
  businesses and, with the extra scope `credentials:read`, fetch their secrets.
539
539
 
540
+ This subpath talks to the English Partner API **`/v3`**
541
+ (`PARTNER_BASE_URL`, `https://api.kasseneck.at/v3`): every field name and
542
+ every value your code branches on is English. Texts for humans (`message`,
543
+ `note`, `statusText`, `nextSteps`) stay German, and so do the error codes for
544
+ now. Everything else in this package (receipts, invoices, the register,
545
+ printing, payments) still uses `/v1` (`DEFAULT_BASE_URL`) until those
546
+ endpoints have a `/v3` of their own.
547
+
540
548
  ```ts
541
549
  import { createPartnerApi, istPartnerFehler } from '@kreiseck/kasseneck-api/partner';
542
550
 
@@ -545,7 +553,7 @@ const partner = createPartnerApi({ partnerKey: process.env.KASSENECK_PARTNER_KEY
545
553
  const { customerId } = await partner.createPartnerCustomer({
546
554
  appId: 'app_…',
547
555
  idempotencyKey: customerNumber, // your own number; protects against duplicates
548
- business, // master data (type Betrieb): name, legal form, address, tax details, contacts
556
+ business, // master data (type Betrieb): legalForm 'sole_proprietor', state 'AT-5', …
549
557
  // env: 'test' is allowed even with a LIVE key: that is how you rehearse the
550
558
  // whole chain without a second key. Never the other way round.
551
559
  });
@@ -572,6 +580,47 @@ try {
572
580
  }
573
581
  ```
574
582
 
583
+ ### Migrating from 0.27.x
584
+
585
+ 0.28.0 is a breaking change for `./partner` only. The client now calls `/v3`
586
+ instead of `/v1`, and `/v3` rejects the German values of `/v1` with
587
+ `validation` instead of translating them. Stored data that goes into
588
+ `createPartnerCustomer` must use the new values:
589
+
590
+ | Where | 0.27.x (`/v1`) | 0.28.0 (`/v3`) |
591
+ |---|---|---|
592
+ | `business.legalForm` | `einzel`, `verein`, `sonstige` | `sole_proprietor`, `association`, `other` (`eu`, `og`, `kg`, `gmbh`, `gmbhcokg`, `ag` unchanged) |
593
+ | `business.state` | `burgenland` … `wien` | `AT-1` … `AT-9` (ISO 3166-2) |
594
+ | `business.contacts[].roles` | `geschaeftsfuehrung`, `buchhaltung`, `technik`, `kasse` | `management`, `accounting`, `technical`, `pos` |
595
+ | `business.taxDetails` | `uid` (type only; the server always wanted `vatId`) | `vatId` |
596
+ | `avv.mode` | `direkt`, `vollmacht`, `unterauftrag` | `direct`, `power_of_attorney`, `subprocessor` |
597
+ | fee on `createPartnerCustomer` / `requestCustomerSignature` | not read (`entgelt {cents, rhythmus, test}`) | `fee {cents, interval, test}`, `interval`: `monthly`, `yearly`, `once` |
598
+ | signature `history[].reason` | `karte_eingetragen`, `fon` | `card_entered`, `finanzonline` |
599
+ | delivery `status`, `lastDelivery.status` | `zugestellt`, `offen`, `fehlgeschlagen`, `verworfen` | `delivered`, `pending`, `failed`, `dropped` |
600
+ | `deletePartnerWebhook` | returned the `webhookId` | returns `{ webhookId, deleted }` |
601
+ | event `customer.terms_accepted` | `kind: 'nutzung'` | `kind: 'terms'` |
602
+ | event `source` | `einrichten`, `prozess`, `partner_vollmacht`, `admin_papier`, `papier_upload` | `setup_link`, `process_link`, `partner_power_of_attorney`, `admin_paper`, `paper_upload` |
603
+
604
+ Field names in this client that were German are English now as well:
605
+ `SignaturStand.signatur` is `signature` (plus `signatures[]`), a request's
606
+ `art` is `kind`, history `von`/`nach` are `from`/`to`,
607
+ `WebhookTestResult.ereignis` is `event`, a delivery's
608
+ `letzterVersuchAt`/`naechsterVersuchAt` are `lastAttemptAt`/`nextAttemptAt`,
609
+ and `requestCustomerSignature(id, { kind })` replaces `{ art }`. A webhook
610
+ now shows `apiVersion` and `lastDelivery { at, status, statusCode }`. The
611
+ types `Rechtsform`, `Bundesland` and `KontaktRolle` remain as deprecated
612
+ aliases of `LegalForm`, `AustrianState` and `ContactRole`.
613
+
614
+ **Webhook payloads have a language of their own.** A webhook created through
615
+ `/v1` keeps sending German payloads (`apiVersion: 'v1'`), whatever path you
616
+ call. Switch it once, there is no way back:
617
+
618
+ ```ts
619
+ await partner.updatePartnerWebhook(webhookId, { apiVersion: 'v3' });
620
+ ```
621
+
622
+ Webhook signature verification is unchanged.
623
+
575
624
  ### A test event is not a cash register
576
625
 
577
626
  `sendPartnerWebhookTest(webhookId, 'cashregister.live')` fires exactly the
@@ -839,13 +888,14 @@ positive for credit notes too; the sign is in the document type
839
888
  (`docType: 'GU'`). Test cases: `fixtures/rechnung-rechnen.json`,
840
889
  `fixtures/rechnung-rechnen-zufall.json`, `fixtures/position-aus-euro.json`.
841
890
 
842
- **`rechnungSummen` still uses the previous formula.** The older helper in
843
- `…/rechnung` works on `unitPriceCents` lines and does not yet run through the
844
- core. At half-cent boundaries it can differ from an invoice issued today by
845
- one cent per VAT rate, and by a few cents across several rates. Example:
846
- € 21.35 net at 10 % gives € 23.48 gross with `rechnungSummen`, but € 23.49
847
- with the core and on the invoice. Use `rechnungRechnen` or `previewInvoice` in
848
- new code. Test cases for the old formula: `fixtures/rechnung-summen.json`.
891
+ **`rechnungSummen` is deprecated.** The older helper in `…/rechnung` works on
892
+ `unitPriceCents` lines with the previous floating-point formula and does not
893
+ run through the core. At half-cent boundaries it can differ from an invoice
894
+ issued today by one cent per VAT rate, and by a few cents across several
895
+ rates. Example: € 21.35 net at 10 % gives € 23.48 gross with `rechnungSummen`,
896
+ but € 23.49 with the core and on the invoice. It stays unchanged for existing
897
+ callers; use `rechnungRechnen` or `previewInvoice` in new code. Test cases for
898
+ the old formula: `fixtures/rechnung-summen.json`.
849
899
 
850
900
  ## Development
851
901
 
@@ -10,9 +10,10 @@
10
10
  * Fehler. Hier steht sie vorher — abfragbar, ausgebbar, und in
11
11
  * [naechsterSchritt] auch beantwortbar.
12
12
  *
13
- * **Ohne Vertragsschritt.** Auftragsverarbeitungsvertraege wirken in diesem
14
- * Weg nicht mehr (Stand 2026-08-31): kein Aufruf meldet einen, keine Kasse
15
- * bleibt deswegen stehen.
13
+ * **Kein eigener Vertragsschritt.** AVV und Nutzungsvertrag bestaetigt der
14
+ * Betrieb ueber denselben Einrichtungs-Link wie seinen FinanzOnline-Zugang
15
+ * (Schritt `fon`). Live geht ohne beide keine Kasse live
16
+ * (`vertrag_offen`); den Stand zeigen `avv` und `terms` am Betrieb.
16
17
  *
17
18
  * Zwei Dinge laufen bewusst **parallel**: der Signaturantrag und das Anlegen
18
19
  * der Kasse. Eine mit `automatic:true` angelegte Kasse wartet, bis die
@@ -11,9 +11,10 @@
11
11
  * Fehler. Hier steht sie vorher — abfragbar, ausgebbar, und in
12
12
  * [naechsterSchritt] auch beantwortbar.
13
13
  *
14
- * **Ohne Vertragsschritt.** Auftragsverarbeitungsvertraege wirken in diesem
15
- * Weg nicht mehr (Stand 2026-08-31): kein Aufruf meldet einen, keine Kasse
16
- * bleibt deswegen stehen.
14
+ * **Kein eigener Vertragsschritt.** AVV und Nutzungsvertrag bestaetigt der
15
+ * Betrieb ueber denselben Einrichtungs-Link wie seinen FinanzOnline-Zugang
16
+ * (Schritt `fon`). Live geht ohne beide keine Kasse live
17
+ * (`vertrag_offen`); den Stand zeigen `avv` und `terms` am Betrieb.
17
18
  *
18
19
  * Zwei Dinge laufen bewusst **parallel**: der Signaturantrag und das Anlegen
19
20
  * der Kasse. Eine mit `automatic:true` angelegte Kasse wartet, bis die
@@ -5,12 +5,27 @@
5
5
  * Funktionen und bleiben einzeln importierbar.
6
6
  */
7
7
  import { type FetchLike } from '../client/transport.js';
8
- import { type CreateWebhookOptions, type CreateWebhookResult, type PartnerWebhook, type WebhookListe, type PartnerWebhookEventType, type WebhookPatch, type WebhookTestResult, type WebhookZustellung } from './webhooks.js';
9
- import type { ActivateCashregisterResult, CreateCashregisterOptions, CreateCashregisterResult, CreateCustomerOptions, CreateCustomerResult, CustomerCredentials, FonLinkResult, KassenListe, Kunde, KundenListe, ListCustomersOptions, PartnerInfo, RequestSignatureResult, SignaturStand } from './typen.js';
8
+ import { type CreateWebhookOptions, type CreateWebhookResult, type DeleteWebhookResult, type PartnerWebhook, type WebhookListe, type PartnerWebhookEventType, type WebhookPatch, type WebhookTestResult, type WebhookZustellung } from './webhooks.js';
9
+ import type { ActivateCashregisterResult, CreateCashregisterOptions, CreateCashregisterResult, CreateCustomerOptions, CreateCustomerResult, CustomerCredentials, FonLinkResult, KassenListe, Kunde, KundenListe, ListCustomersOptions, PartnerInfo, RequestSignatureOptions, RequestSignatureResult, SignaturStand } from './typen.js';
10
+ /**
11
+ * Die Basis-URL der Partner-API: `/v3`, die englische Fassung.
12
+ *
13
+ * Nur der Partner-Teil spricht `/v3`. Belege, Rechnungen, Kasse und Zahlungen
14
+ * laufen weiter ueber [DEFAULT_BASE_URL] (`/v1`), bis es fuer sie eine `/v3`
15
+ * gibt. Die Partner-Endpunkte unter `/v1` antworten weiter, deutsch und
16
+ * abgekuendigt (Kopfzeilen `Deprecation`/`Sunset`); dieser Client spricht sie
17
+ * nicht mehr.
18
+ */
19
+ export declare const PARTNER_BASE_URL = "https://api.kasseneck.at/v3";
10
20
  export interface PartnerApiOptions {
11
21
  /** Partner-Schluessel `pk_test_…` / `pk_live_…`. Gehoert auf einen Server. */
12
22
  partnerKey: string;
13
- /** Abweichende Basis-URL; Vorgabe `https://api.kasseneck.at/v1`. */
23
+ /**
24
+ * Abweichende Basis-URL; Vorgabe [PARTNER_BASE_URL]
25
+ * (`https://api.kasseneck.at/v3`). Die Antworten werden in der Form der
26
+ * `/v3` gelesen: eine `/v1`-Adresse hier liefert deutsche Werte, die diese
27
+ * Typen nicht beschreiben.
28
+ */
14
29
  baseUrl?: string;
15
30
  /** Zeitlimit je Aufruf in Millisekunden. */
16
31
  timeoutMs?: number;
@@ -23,10 +38,7 @@ export interface PartnerApi {
23
38
  listPartnerCustomers(optionen?: ListCustomersOptions): Promise<KundenListe>;
24
39
  getPartnerCustomer(customerId: string): Promise<Kunde>;
25
40
  sendPartnerCustomerFonLink(customerId: string): Promise<FonLinkResult>;
26
- requestCustomerSignature(customerId: string, optionen?: {
27
- art?: string;
28
- additional?: boolean;
29
- }): Promise<RequestSignatureResult>;
41
+ requestCustomerSignature(customerId: string, optionen?: RequestSignatureOptions): Promise<RequestSignatureResult>;
30
42
  getCustomerSignatureStatus(customerId: string): Promise<SignaturStand>;
31
43
  createCustomerCashregister(optionen: CreateCashregisterOptions): Promise<CreateCashregisterResult>;
32
44
  activateCashregister(customerId: string, cashregisterId: string): Promise<ActivateCashregisterResult>;
@@ -42,7 +54,7 @@ export interface PartnerApi {
42
54
  createPartnerWebhook(optionen: CreateWebhookOptions): Promise<CreateWebhookResult>;
43
55
  listPartnerWebhooks(): Promise<WebhookListe>;
44
56
  updatePartnerWebhook(webhookId: string, patch: WebhookPatch): Promise<PartnerWebhook>;
45
- deletePartnerWebhook(webhookId: string): Promise<string>;
57
+ deletePartnerWebhook(webhookId: string): Promise<DeleteWebhookResult>;
46
58
  /**
47
59
  * Neues Secret fuer denselben Endpunkt — dieselbe `webhookId`, dieselben
48
60
  * Ereignisse. Das alte gilt ab der Antwort nicht mehr.
@@ -6,16 +6,27 @@
6
6
  * Funktionen und bleiben einzeln importierbar.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.PARTNER_BASE_URL = void 0;
9
10
  exports.createPartnerApi = createPartnerApi;
10
11
  const transport_js_1 = require("../client/transport.js");
11
12
  const auth_js_1 = require("./auth.js");
12
13
  const fehler_js_1 = require("./fehler.js");
13
14
  const endpunkte_js_1 = require("./endpunkte.js");
14
15
  const webhooks_js_1 = require("./webhooks.js");
16
+ /**
17
+ * Die Basis-URL der Partner-API: `/v3`, die englische Fassung.
18
+ *
19
+ * Nur der Partner-Teil spricht `/v3`. Belege, Rechnungen, Kasse und Zahlungen
20
+ * laufen weiter ueber [DEFAULT_BASE_URL] (`/v1`), bis es fuer sie eine `/v3`
21
+ * gibt. Die Partner-Endpunkte unter `/v1` antworten weiter, deutsch und
22
+ * abgekuendigt (Kopfzeilen `Deprecation`/`Sunset`); dieser Client spricht sie
23
+ * nicht mehr.
24
+ */
25
+ exports.PARTNER_BASE_URL = 'https://api.kasseneck.at/v3';
15
26
  function createPartnerApi(optionen) {
16
27
  const rufen = (0, transport_js_1.createTransport)({
17
28
  auth: (0, auth_js_1.partnerKeyAuth)({ partnerKey: optionen.partnerKey }),
18
- baseUrl: optionen.baseUrl,
29
+ baseUrl: optionen.baseUrl ?? exports.PARTNER_BASE_URL,
19
30
  timeoutMs: optionen.timeoutMs,
20
31
  fetch: optionen.fetch,
21
32
  });
@@ -19,7 +19,7 @@
19
19
  * einen `TypeError` an unpassender Stelle.
20
20
  */
21
21
  import type { InternerTransport } from '../client/aufrufe.js';
22
- import type { ActivateCashregisterResult, CreateCashregisterOptions, CreateCashregisterResult, CreateCustomerOptions, CreateCustomerResult, CustomerCredentials, FonLinkResult, KassenListe, Kunde, KundenListe, ListCustomersOptions, PartnerInfo, RequestSignatureResult, SignaturStand } from './typen.js';
22
+ import type { ActivateCashregisterResult, CreateCashregisterOptions, CreateCashregisterResult, CreateCustomerOptions, CreateCustomerResult, CustomerCredentials, FonLinkResult, KassenListe, Kunde, KundenListe, ListCustomersOptions, PartnerInfo, RequestSignatureOptions, RequestSignatureResult, SignaturStand } from './typen.js';
23
23
  /**
24
24
  * Wer bin ich, in welcher Umgebung, mit welchen Rechten — und welche Apps
25
25
  * gehoeren mir. `apps[].id` ist die `appId` fuer [createPartnerCustomer].
@@ -76,8 +76,8 @@ export declare function sendPartnerCustomerFonLink(rufen: InternerTransport, cus
76
76
  * Vertrauensdiensteanbieter **auf diesen Betrieb** ausstellen und meldet sie
77
77
  * bei FinanzOnline an; einen Vorrat fertiger Karten gibt es nicht.
78
78
  *
79
- * Der Antrag erzeugt sofort ein Signatur-OBJEKT: `antrag.requestId` ist
80
- * zugleich die `signaturId`, auf die sich eine Kasse beruft — auch solange
79
+ * Der Antrag erzeugt sofort ein Signatur-OBJEKT: `request.requestId` ist
80
+ * zugleich die `signatureRequestId`, auf die sich eine Kasse beruft — auch solange
81
81
  * noch keine Karte zugewiesen ist.
82
82
  *
83
83
  * **Je Betrieb laeuft nur ein Antrag.** Ein zweiter Aufruf liefert den
@@ -87,23 +87,20 @@ export declare function sendPartnerCustomerFonLink(rufen: InternerTransport, cus
87
87
  * Abschluss kommt als Ereignis `signature.ready`, nicht als Antwort auf diesen
88
88
  * Aufruf.
89
89
  */
90
- export declare function requestCustomerSignature(rufen: InternerTransport, customerId: string, optionen?: {
91
- art?: string;
92
- additional?: boolean;
93
- }): Promise<RequestSignatureResult>;
94
- /** Stand der Signatur eines Betriebs samt aller Antraege und des FON-Zugangs. */
90
+ export declare function requestCustomerSignature(rufen: InternerTransport, customerId: string, optionen?: RequestSignatureOptions): Promise<RequestSignatureResult>;
91
+ /** Stand der Signatur eines Betriebs samt aller Signaturen, Antraege und des FON-Zugangs. */
95
92
  export declare function getCustomerSignatureStatus(rufen: InternerTransport, customerId: string): Promise<SignaturStand>;
96
93
  /**
97
94
  * Legt eine Kasse an.
98
95
  *
99
96
  * **Jede Kasse bezieht sich auf eine Signatur.** Ohne eine einzige — auch eine
100
97
  * noch laufende zaehlt — entsteht keine (`signature_missing`); bei mehreren
101
- * muss `signaturId` dastehen (`signature_ambiguous`).
98
+ * muss `signatureRequestId` dastehen (`signature_ambiguous`).
102
99
  *
103
100
  * **Darf vor der fertigen Signatur aufgerufen werden:** die Kasse bleibt dann
104
- * auf `entwurf` und geht von selbst live, sobald IHRE Signatur bereit ist
105
- * (`automatic:true`, Vorgabe). `inbetriebnahme.reason` sagt, warum gerade
106
- * nichts lief: `signature_not_ready` oder `automatik_aus`.
101
+ * auf `draft` und geht von selbst live, sobald IHRE Signatur bereit ist
102
+ * (`automatic:true`, Vorgabe). `activation.reason` sagt, warum gerade
103
+ * nichts lief: `signature_not_ready` oder `automation_off`.
107
104
  *
108
105
  * Hoechstens 20 Kassen je Betrieb (`cashregister_limit`); ohne gebuchtes Modul
109
106
  * `module_inactive`.
@@ -59,6 +59,19 @@ function zahlOderNull(wert) {
59
59
  function jaNein(wert, rueckfall = false) {
60
60
  return typeof wert === 'boolean' ? wert : rueckfall;
61
61
  }
62
+ /**
63
+ * Das gebuchte Entgelt (`fee`), falls die Antwort eines fuehrt. Ohne Betrag
64
+ * ist es keines: ein erfundenes `0` saehe aus wie ein kostenloser Posten.
65
+ */
66
+ function entgelt(wert) {
67
+ if (wert === null || typeof wert !== 'object' || Array.isArray(wert))
68
+ return null;
69
+ const f = wert;
70
+ const cents = zahlOderNull(f['cents']);
71
+ if (cents === null)
72
+ return null;
73
+ return { cents, interval: text(f['interval']), test: jaNein(f['test']) };
74
+ }
62
75
  /**
63
76
  * Verlangt ein Feld der Antwort. Der Fehler nennt das Feld und den Vorgang,
64
77
  * damit ein Aufrufer nicht raten muss, welcher der Aufrufe etwas anderes
@@ -172,6 +185,7 @@ async function createPartnerCustomer(rufen, optionen) {
172
185
  appId: text(daten['appId'], appId),
173
186
  access: { invited: jaNein(zugang['invited']), sentTo: textOderNull(zugang['sentTo']) },
174
187
  nextSteps: liste(daten['nextSteps']).filter((s) => typeof s === 'string'),
188
+ fee: entgelt(daten['fee']),
175
189
  replayed: jaNein(daten['replayed']),
176
190
  };
177
191
  }
@@ -200,26 +214,38 @@ function kundenZeile(eintrag) {
200
214
  appId: textOderNull(k['appId']),
201
215
  env: text(k['env']) === 'test' ? 'test' : 'live',
202
216
  createdAt: zahlOderNull(k['createdAt']),
217
+ fon: fonStand(k['fon']),
203
218
  avv: avvStand(k['avv']),
219
+ terms: vertragStand(k['terms']),
204
220
  };
205
221
  }
206
- /**
207
- * Der Vertragsstand, **falls** die Antwort ihn ueberhaupt fuehrt — heute tut
208
- * sie das nicht, dann bleibt es bei `null`. Kein erfundenes `offen`: „nicht
209
- * mitgeliefert" und „nicht bestaetigt" duerfen fuer einen Aufrufer nicht
210
- * dasselbe sein.
211
- */
212
- function avvStand(wert) {
222
+ function fonStand(wert) {
213
223
  if (wert === null || typeof wert !== 'object' || Array.isArray(wert))
214
224
  return null;
215
- const a = wert;
225
+ const f = wert;
216
226
  return {
217
- status: text(a['status']),
218
- version: textOderNull(a['version']),
219
- confirmedAt: zahlOderNull(a['confirmedAt']),
220
- mode: textOderNull(a['mode']),
227
+ configured: jaNein(f['configured']),
228
+ linkSentAt: zahlOderNull(f['linkSentAt']),
229
+ linkOpenedAt: zahlOderNull(f['linkOpenedAt']),
221
230
  };
222
231
  }
232
+ function vertragStand(wert) {
233
+ if (wert === null || typeof wert !== 'object' || Array.isArray(wert))
234
+ return null;
235
+ const v = wert;
236
+ return { status: text(v['status']), version: textOderNull(v['version']), confirmedAt: zahlOderNull(v['confirmedAt']) };
237
+ }
238
+ /**
239
+ * Der AVV-Stand, **falls** die Antwort ihn fuehrt; sonst `null`. Kein
240
+ * erfundenes `pending`: „nicht mitgeliefert" und „nicht bestaetigt" duerfen
241
+ * fuer einen Aufrufer nicht dasselbe sein.
242
+ */
243
+ function avvStand(wert) {
244
+ const v = vertragStand(wert);
245
+ if (!v)
246
+ return null;
247
+ return { ...v, mode: textOderNull(wert['mode']) };
248
+ }
223
249
  /** Ein Betrieb mit allem, was der Partner ueber ihn sehen darf — nie Geheimnisse. */
224
250
  async function getPartnerCustomer(rufen, customerId) {
225
251
  const id = pflicht(customerId, 'getPartnerCustomer', 'customerId');
@@ -234,7 +260,13 @@ async function getPartnerCustomer(rufen, customerId) {
234
260
  createdAt: zahlOderNull(k['createdAt']),
235
261
  createdVia: textOderNull(k['createdVia']),
236
262
  business: objekt(k['business']),
237
- fon: { configured: jaNein(fon['configured']), verifiedAt: zahlOderNull(fon['verifiedAt']) },
263
+ fon: {
264
+ configured: jaNein(fon['configured']),
265
+ verifiedAt: zahlOderNull(fon['verifiedAt']),
266
+ linkSentAt: zahlOderNull(fon['linkSentAt']),
267
+ linkSentTo: textOderNull(fon['linkSentTo']),
268
+ linkOpenedAt: zahlOderNull(fon['linkOpenedAt']),
269
+ },
238
270
  access: zugang === null || typeof zugang !== 'object'
239
271
  ? null
240
272
  : {
@@ -288,7 +320,7 @@ function antrag(eintrag) {
288
320
  requestId: text(a['requestId']),
289
321
  status: text(a['status']),
290
322
  statusText: text(a['statusText']),
291
- art: text(a['art'], 'signature_card'),
323
+ kind: text(a['kind'], 'signature_card'),
292
324
  vdaId: textOderNull(a['vdaId']),
293
325
  signatureId: textOderNull(a['signatureId']),
294
326
  error: fehler === null || typeof fehler !== 'object'
@@ -304,8 +336,8 @@ function antrag(eintrag) {
304
336
  history: liste(a['history']).map((h) => {
305
337
  const e = objekt(h);
306
338
  return {
307
- von: textOderNull(e['von']),
308
- nach: text(e['nach']),
339
+ from: textOderNull(e['from']),
340
+ to: text(e['to']),
309
341
  at: zahlOderNull(e['at']) ?? 0,
310
342
  reason: textOderNull(e['reason']),
311
343
  };
@@ -317,8 +349,8 @@ function antrag(eintrag) {
317
349
  * Vertrauensdiensteanbieter **auf diesen Betrieb** ausstellen und meldet sie
318
350
  * bei FinanzOnline an; einen Vorrat fertiger Karten gibt es nicht.
319
351
  *
320
- * Der Antrag erzeugt sofort ein Signatur-OBJEKT: `antrag.requestId` ist
321
- * zugleich die `signaturId`, auf die sich eine Kasse beruft — auch solange
352
+ * Der Antrag erzeugt sofort ein Signatur-OBJEKT: `request.requestId` ist
353
+ * zugleich die `signatureRequestId`, auf die sich eine Kasse beruft — auch solange
322
354
  * noch keine Karte zugewiesen ist.
323
355
  *
324
356
  * **Je Betrieb laeuft nur ein Antrag.** Ein zweiter Aufruf liefert den
@@ -332,27 +364,54 @@ async function requestCustomerSignature(rufen, customerId, optionen = {}) {
332
364
  const id = pflicht(customerId, 'requestCustomerSignature', 'customerId');
333
365
  const daten = objekt(await rufen('requestCustomerSignature', {
334
366
  customerId: id,
335
- art: optionen.art,
367
+ kind: optionen.kind,
336
368
  additional: optionen.additional,
337
369
  }));
338
370
  return {
339
371
  request: antrag(verlangt(daten['request'], 'requestCustomerSignature', 'request')),
340
372
  replayed: jaNein(daten['replayed']),
341
373
  note: textOderNull(daten['note']),
374
+ fee: entgelt(daten['fee']),
342
375
  };
343
376
  }
344
- /** Stand der Signatur eines Betriebs samt aller Antraege und des FON-Zugangs. */
377
+ function signaturEinzeln(eintrag) {
378
+ const s = objekt(eintrag);
379
+ const fehler = s['error'];
380
+ return {
381
+ signatureRequestId: text(s['signatureRequestId']),
382
+ status: text(s['status']),
383
+ statusText: text(s['statusText']),
384
+ inProgress: jaNein(s['inProgress']),
385
+ ready: jaNein(s['ready']),
386
+ kind: text(s['kind'], 'signature_card'),
387
+ vdaId: textOderNull(s['vdaId']),
388
+ requestId: textOderNull(s['requestId']),
389
+ signatureId: textOderNull(s['signatureId']),
390
+ error: fehler === null || typeof fehler !== 'object'
391
+ ? null
392
+ : {
393
+ code: textOderNull(objekt(fehler)['code']),
394
+ message: textOderNull(objekt(fehler)['message']),
395
+ rc: textOderNull(objekt(fehler)['rc']),
396
+ },
397
+ createdAt: zahlOderNull(s['createdAt']),
398
+ updatedAt: zahlOderNull(s['updatedAt']),
399
+ };
400
+ }
401
+ /** Stand der Signatur eines Betriebs samt aller Signaturen, Antraege und des FON-Zugangs. */
345
402
  async function getCustomerSignatureStatus(rufen, customerId) {
346
403
  const id = pflicht(customerId, 'getCustomerSignatureStatus', 'customerId');
347
404
  const daten = objekt(await rufen('getCustomerSignatureStatus', { customerId: id }));
348
- const signatur = objekt(daten['signatur']);
405
+ const signatur = objekt(daten['signature']);
349
406
  const fon = objekt(daten['fon']);
350
407
  return {
351
- signatur: {
408
+ customerId: text(daten['customerId'], id),
409
+ signature: {
352
410
  ready: jaNein(signatur['ready']),
353
411
  signatureId: textOderNull(signatur['signatureId']),
354
412
  vdaId: textOderNull(signatur['vdaId']),
355
413
  },
414
+ signatures: liste(daten['signatures']).map(signaturEinzeln),
356
415
  requests: liste(daten['requests']).map(antrag),
357
416
  fon: { present: jaNein(fon['present']), verifiedAt: zahlOderNull(fon['verifiedAt']) },
358
417
  };
@@ -392,12 +451,12 @@ function kasse(eintrag) {
392
451
  *
393
452
  * **Jede Kasse bezieht sich auf eine Signatur.** Ohne eine einzige — auch eine
394
453
  * noch laufende zaehlt — entsteht keine (`signature_missing`); bei mehreren
395
- * muss `signaturId` dastehen (`signature_ambiguous`).
454
+ * muss `signatureRequestId` dastehen (`signature_ambiguous`).
396
455
  *
397
456
  * **Darf vor der fertigen Signatur aufgerufen werden:** die Kasse bleibt dann
398
- * auf `entwurf` und geht von selbst live, sobald IHRE Signatur bereit ist
399
- * (`automatic:true`, Vorgabe). `inbetriebnahme.reason` sagt, warum gerade
400
- * nichts lief: `signature_not_ready` oder `automatik_aus`.
457
+ * auf `draft` und geht von selbst live, sobald IHRE Signatur bereit ist
458
+ * (`automatic:true`, Vorgabe). `activation.reason` sagt, warum gerade
459
+ * nichts lief: `signature_not_ready` oder `automation_off`.
401
460
  *
402
461
  * Hoechstens 20 Kassen je Betrieb (`cashregister_limit`); ohne gebuchtes Modul
403
462
  * `module_inactive`.
@@ -27,7 +27,7 @@
27
27
  *
28
28
  * Reihenfolge und Bestand wie im Abzug des Backends.
29
29
  */
30
- export declare const PARTNER_FEHLER_CODES: readonly ["validation", "rate_limited", "app_not_found", "app_not_accepted", "kein_partnerbetrieb", "live_not_allowed", "customer_exists", "customer_conflict", "customer_limit", "zugang_nicht_erlaubt", "email_taken", "no_email", "fon_missing", "signature_pending", "request_not_found", "signature_missing", "signature_unknown", "signature_ambiguous", "signature_not_ready", "signature_limit", "signature_failed", "module_inactive", "cashregister_limit", "cashregister_not_found", "activation_failed", "webhook_limit", "webhook_inactive", "event_not_subscribed"];
30
+ export declare const PARTNER_FEHLER_CODES: readonly ["validation", "rate_limited", "app_not_found", "app_not_accepted", "kein_partnerbetrieb", "live_not_allowed", "customer_exists", "customer_conflict", "customer_limit", "zugang_nicht_erlaubt", "email_taken", "no_email", "kennung_fehlt", "fon_missing", "signature_pending", "request_not_found", "signature_missing", "signature_unknown", "signature_ambiguous", "signature_not_ready", "signature_limit", "signature_failed", "module_inactive", "cashregister_limit", "cashregister_not_found", "vertrag_offen", "activation_failed", "webhook_limit", "webhook_inactive", "event_not_subscribed"];
31
31
  /**
32
32
  * Die Codes, die nur im **Partner-Portal** entstehen — beim Pflegen der App,
33
33
  * der Schluessel, der Mitglieder und der Signaturkarten.
@@ -53,6 +53,8 @@ exports.PARTNER_FEHLER_CODES = [
53
53
  'zugang_nicht_erlaubt',
54
54
  'email_taken',
55
55
  'no_email',
56
+ // FinanzOnline-Link
57
+ 'kennung_fehlt',
56
58
  // Signatur
57
59
  'fon_missing',
58
60
  'signature_pending',
@@ -67,6 +69,7 @@ exports.PARTNER_FEHLER_CODES = [
67
69
  'module_inactive',
68
70
  'cashregister_limit',
69
71
  'cashregister_not_found',
72
+ 'vertrag_offen',
70
73
  'activation_failed',
71
74
  // Webhooks
72
75
  'webhook_limit',
@@ -121,21 +124,23 @@ const RAT = {
121
124
  customer_exists: 'Diesen Betrieb gibt es schon (data.customerId). Mit derselben customerId weiterarbeiten.',
122
125
  customer_conflict: 'Die Steuernummer ist bei Kasseneck bereits registriert. Die Zuordnung zum Partner macht Kasseneck — hello@kasseneck.at.',
123
126
  customer_limit: 'Das Tageslimit fuer neue Betriebe ist erreicht (data.max, data.resetAt). Morgen weiter.',
124
- zugang_nicht_erlaubt: 'Fuer dieses Partner-Konto sind Zugaenge zum Kundenpanel nicht freigeschaltet — es entstand NICHTS, auch kein Betrieb. Ohne zugang{invite:true} erneut anlegen oder die Freischaltung erfragen (Stand: getPartnerInfo.partner.canCreateAccess).',
127
+ zugang_nicht_erlaubt: 'Fuer dieses Partner-Konto sind Zugaenge zum Kundenpanel nicht freigeschaltet — es entstand NICHTS, auch kein Betrieb. Ohne access{invite:true} erneut anlegen oder die Freischaltung erfragen (Stand: getPartnerInfo.partner.canCreateAccess).',
125
128
  email_taken: 'Fuer diese E-Mail gibt es schon einen Kasseneck-Zugang. Eine andere Adresse waehlen, auf die Einladung verzichten oder den Betrieb zuordnen lassen.',
126
129
  no_email: 'Im Konto des Betriebs steht keine E-Mail-Adresse. Ohne sie geht weder eine Einladung noch der FinanzOnline-Link hinaus.',
130
+ kennung_fehlt: 'Am Betrieb ist keine Steuernummer hinterlegt, ohne sie gibt es keinen Einrichtungs-Link. Die Steuernummer bei Kasseneck nachtragen lassen (hello@kasseneck.at), dann sendPartnerCustomerFonLink erneut.',
127
131
  fon_missing: 'Der Betrieb hat noch keinen FinanzOnline-Zugang. sendPartnerCustomerFonLink senden und customer.fon_verified abwarten. Betrifft das ANMELDEN der Signatureinheit, nicht das Beantragen.',
128
132
  signature_pending: 'Fuer diesen Betrieb laeuft bereits ein Antrag. Auf signature.ready warten.',
129
133
  request_not_found: 'Diese signaturId gibt es nicht. getCustomerSignatureStatus nennt die des Betriebs.',
130
134
  signature_missing: 'Der Betrieb hat ueberhaupt keine Signatur, und jede Kasse bezieht sich auf eine. Zuerst requestCustomerSignature.',
131
- signature_unknown: 'Die genannte signaturId gehoert nicht zu diesem Betrieb. getCustomerSignatureStatus nennt die seinen.',
132
- signature_ambiguous: 'Der Betrieb hat mehrere Signaturen; welche die Kasse benutzt, muss dastehen. Eine aus data.choices als signaturId mitgeben.',
135
+ signature_unknown: 'Die genannte signatureRequestId gehoert nicht zu diesem Betrieb. getCustomerSignatureStatus nennt die seinen.',
136
+ signature_ambiguous: 'Der Betrieb hat mehrere Signaturen; welche die Kasse benutzt, muss dastehen. Eine aus data.choices als signatureRequestId mitgeben.',
133
137
  signature_not_ready: 'Die Signatur DIESER Kasse ist noch nicht bereit. Auf signature.ready warten; eine mit automatic:true angelegte Kasse geht danach von selbst live.',
134
138
  signature_limit: 'Hoechstens zehn Signaturen je Betrieb. Eine bestehende benutzen, statt mit additional:true eine weitere zu beantragen.',
135
139
  signature_failed: 'FinanzOnline hat die Anmeldung abgelehnt (data.rc). Kasseneck klaert das — hello@kasseneck.at.',
136
140
  module_inactive: 'Das Modul (data.modul) ist fuer diesen Betrieb nicht gebucht. Kasseneck schaltet es frei.',
137
141
  cashregister_limit: 'Hoechstens 20 Registrierkassen je Betrieb. Eine bestehende nutzen.',
138
142
  cashregister_not_found: 'Diese cashregisterId gibt es bei diesem Betrieb nicht.',
143
+ vertrag_offen: 'Nur live: der Betrieb hat Auftragsverarbeitungs- und Nutzungsvertrag noch nicht bestaetigt. An der Kasse aendert sich nichts. Den Betrieb ueber den Einrichtungs-Link bestaetigen lassen (sendPartnerCustomerFonLink, Stand in avv/terms von getPartnerCustomer), danach activateCashregister erneut.',
139
144
  activation_failed: 'Die Inbetriebnahme blieb an data.step haengen (ggf. data.rc). activateCashregister erneut aufrufen — jeder Schritt ist idempotent, der Lauf setzt an der Bruchstelle an.',
140
145
  webhook_limit: 'Hoechstens 10 Webhook-Endpunkte je Partner. Einen ungenutzten loeschen.',
141
146
  webhook_inactive: 'Der Webhook steht auf active:false. Zuerst aktivieren, dann erneut proben.',