@kreiseck/kasseneck-api 1.5.0 → 1.6.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 (90) hide show
  1. package/CHANGELOG.md +124 -0
  2. package/README.md +181 -27
  3. package/dist/cjs/client/aufrufe.d.ts +58 -4
  4. package/dist/cjs/client/aufrufe.js +185 -1
  5. package/dist/cjs/client/errors.d.ts +32 -19
  6. package/dist/cjs/client/errors.js +28 -17
  7. package/dist/cjs/client/index.d.ts +2 -2
  8. package/dist/cjs/client/index.js +2 -1
  9. package/dist/cjs/client/transport.d.ts +27 -1
  10. package/dist/cjs/client/transport.js +25 -27
  11. package/dist/cjs/index.d.ts +1 -1
  12. package/dist/cjs/index.js +3 -2
  13. package/dist/cjs/inventory/api.d.ts +10 -2
  14. package/dist/cjs/inventory/api.js +8 -1
  15. package/dist/cjs/inventory/endpunkte.d.ts +2 -1
  16. package/dist/cjs/inventory/endpunkte.js +2 -1
  17. package/dist/cjs/inventory/index.d.ts +5 -3
  18. package/dist/cjs/inventory/index.js +15 -3
  19. package/dist/cjs/inventory/lesen.d.ts +7 -1
  20. package/dist/cjs/inventory/lesen.js +75 -0
  21. package/dist/cjs/inventory/schreiben.d.ts +26 -1
  22. package/dist/cjs/inventory/schreiben.js +24 -10
  23. package/dist/cjs/inventory/typen.d.ts +156 -2
  24. package/dist/cjs/inventory/varianten.d.ts +67 -0
  25. package/dist/cjs/inventory/varianten.js +150 -0
  26. package/dist/cjs/inventory/vertrag.d.ts +40 -5
  27. package/dist/cjs/inventory/vertrag.js +51 -3
  28. package/dist/cjs/inventory/webhook.d.ts +5 -2
  29. package/dist/cjs/inventory/webhook.js +8 -2
  30. package/dist/cjs/invoice/endpunkte.d.ts +6 -0
  31. package/dist/cjs/invoice/endpunkte.js +13 -2
  32. package/dist/cjs/pos/texte.d.ts +11 -6
  33. package/dist/cjs/pos/texte.js +11 -6
  34. package/dist/cjs/stored/vokabular.d.ts +1 -1
  35. package/dist/cjs/stored/vokabular.js +1 -1
  36. package/dist/cjs/version.d.ts +1 -1
  37. package/dist/cjs/version.js +1 -1
  38. package/dist/esm/client/aufrufe.d.ts +58 -4
  39. package/dist/esm/client/aufrufe.js +183 -0
  40. package/dist/esm/client/errors.d.ts +32 -19
  41. package/dist/esm/client/errors.js +28 -17
  42. package/dist/esm/client/index.d.ts +2 -2
  43. package/dist/esm/client/index.js +1 -1
  44. package/dist/esm/client/transport.d.ts +27 -1
  45. package/dist/esm/client/transport.js +26 -28
  46. package/dist/esm/index.d.ts +1 -1
  47. package/dist/esm/index.js +1 -1
  48. package/dist/esm/inventory/api.d.ts +10 -2
  49. package/dist/esm/inventory/api.js +8 -1
  50. package/dist/esm/inventory/endpunkte.d.ts +2 -1
  51. package/dist/esm/inventory/endpunkte.js +2 -1
  52. package/dist/esm/inventory/index.d.ts +5 -3
  53. package/dist/esm/inventory/index.js +4 -2
  54. package/dist/esm/inventory/lesen.d.ts +7 -1
  55. package/dist/esm/inventory/lesen.js +74 -0
  56. package/dist/esm/inventory/schreiben.d.ts +26 -1
  57. package/dist/esm/inventory/schreiben.js +19 -11
  58. package/dist/esm/inventory/typen.d.ts +156 -2
  59. package/dist/esm/inventory/varianten.d.ts +67 -0
  60. package/dist/esm/inventory/varianten.js +142 -0
  61. package/dist/esm/inventory/vertrag.d.ts +40 -5
  62. package/dist/esm/inventory/vertrag.js +50 -2
  63. package/dist/esm/inventory/webhook.d.ts +5 -2
  64. package/dist/esm/inventory/webhook.js +9 -3
  65. package/dist/esm/invoice/endpunkte.d.ts +6 -0
  66. package/dist/esm/invoice/endpunkte.js +13 -2
  67. package/dist/esm/pos/texte.d.ts +11 -6
  68. package/dist/esm/pos/texte.js +11 -6
  69. package/dist/esm/stored/vokabular.d.ts +1 -1
  70. package/dist/esm/stored/vokabular.js +1 -1
  71. package/dist/esm/version.d.ts +1 -1
  72. package/dist/esm/version.js +1 -1
  73. package/fixtures/hobex-hps-codes.json +1 -1
  74. package/fixtures/invoice-api.schema.json +1 -1
  75. package/fixtures/invoice-texts.json +1 -1
  76. package/fixtures/pos-texts.json +1 -1
  77. package/fixtures/surface.json +85 -6
  78. package/fixtures/v3/antworten/belege.json +1 -1
  79. package/fixtures/v3/antworten/belegmail.json +1 -1
  80. package/fixtures/v3/antworten/kasse-belege.json +1 -1
  81. package/fixtures/v3/antworten/kasse.json +2 -2
  82. package/fixtures/v3/antworten/lager.json +2396 -4
  83. package/fixtures/v3/antworten/rechnungen.json +1 -1
  84. package/fixtures/v3/antworten/storno.json +1 -1
  85. package/fixtures/v3/stored/belege.json +1 -1
  86. package/fixtures/v3/stored/kasse.json +2 -2
  87. package/fixtures/v3/stored/rechnungen.json +1 -1
  88. package/fixtures/v3/v3-vokabular.json +151 -6
  89. package/fixtures/v3/zahlbetrag-faelle.json +1 -1
  90. package/package.json +1 -1
@@ -19,7 +19,7 @@ import type { InventoryWarningCode, InventoryWebhookEventType, LandedCostAllocat
19
19
  * `purchasePriceMicros` nur mit dem Recht `costs` (Konto-Schalter
20
20
  * `lagerApi.kosten`, sonst fehlt das Feld, nicht `null`), `externalIds`,
21
21
  * `metadata`, `variantGroupId` und `variantAttributes` nur, wenn der Artikel
22
- * sie traegt.
22
+ * sie traegt (eine Variante, siehe [VariantGroup]).
23
23
  */
24
24
  export interface Article {
25
25
  id: string;
@@ -59,7 +59,14 @@ export interface Article {
59
59
  active: boolean;
60
60
  externalIds?: Record<string, string>;
61
61
  metadata?: Record<string, string>;
62
+ /** Nur an einer Variante: die Variantengruppe. Gesetzt nur ueber `createVariantGroup`/`addVariant`, nie umgehaengt. */
62
63
  variantGroupId?: string;
64
+ /**
65
+ * Nur an einer Variante: je Merkmal der Gruppe genau ein Wert
66
+ * (`{ farbe: 'rot', groesse: 'S' }`). Die Schluessel kommen nach Codepunkt
67
+ * sortiert, nicht in der Merkmalsreihenfolge der Gruppe; die steht in
68
+ * [VariantGroup.attributes].
69
+ */
63
70
  variantAttributes?: Record<string, string>;
64
71
  createdAt: string | null;
65
72
  updatedAt: string | null;
@@ -78,6 +85,12 @@ export interface ArticleListQuery {
78
85
  */
79
86
  updatedSince?: string | Date;
80
87
  groupId?: string;
88
+ /**
89
+ * Nur die Varianten dieser Gruppe (Backend ab Stufe 5c), wie ohne Filter
90
+ * nach `updatedAt` aufsteigend; mit `updatedSince` der Abgleich
91
+ * einer Gruppe. Die Artikel einer neuen Gruppe liest man so, die Antwort von
92
+ * `createVariantGroup` traegt nur ihre Kennungen.
93
+ */
81
94
  variantGroupId?: string;
82
95
  active?: boolean;
83
96
  stockTracked?: boolean;
@@ -342,7 +355,7 @@ export interface InventoryWebhookEnvelope<T extends InventoryWebhookEventType, D
342
355
  test: boolean;
343
356
  data: D;
344
357
  }
345
- export type InventoryWebhookEvent = InventoryWebhookEnvelope<'stock.changed', StockChangedEventData> | InventoryWebhookEnvelope<'stock.below_minimum', StockBelowMinimumEventData> | InventoryWebhookEnvelope<'article.created', Article> | InventoryWebhookEnvelope<'article.updated', Article> | InventoryWebhookEnvelope<'article.deactivated', Article> | InventoryWebhookEnvelope<'reservation.expired', Reservation> | InventoryWebhookEnvelope<'reservation.released', Reservation> | InventoryWebhookEnvelope<'reservation.redeemed', Reservation>;
358
+ export type InventoryWebhookEvent = InventoryWebhookEnvelope<'stock.changed', StockChangedEventData> | InventoryWebhookEnvelope<'stock.below_minimum', StockBelowMinimumEventData> | InventoryWebhookEnvelope<'article.created', Article> | InventoryWebhookEnvelope<'article.updated', Article> | InventoryWebhookEnvelope<'article.deactivated', Article> | InventoryWebhookEnvelope<'reservation.expired', Reservation> | InventoryWebhookEnvelope<'reservation.released', Reservation> | InventoryWebhookEnvelope<'reservation.redeemed', Reservation> | InventoryWebhookEnvelope<'variant_group.created', VariantGroup> | InventoryWebhookEnvelope<'variant_group.updated', VariantGroup>;
346
359
  /**
347
360
  * Die Felder eines Artikels beim Anlegen. Bei der Anlage heisst `null` „nicht
348
361
  * angegeben“ (ausser bei `name`, der Pflicht ist).
@@ -677,3 +690,144 @@ export interface InventoryShortfall {
677
690
  /** Verfuegbar (`onHand − reserved`), Tausendstel; darf negativ sein. */
678
691
  available: number;
679
692
  }
693
+ /** Ein Merkmal einer Variantengruppe mit seinen Werten, in der Reihenfolge der Gruppe. */
694
+ export interface VariantAttribute {
695
+ /** `^[a-z0-9_]{1,32}$`, eindeutig in der Gruppe; Schluessel in `variantAttributes`. */
696
+ key: string;
697
+ /** Beschriftung, 1–40 Zeichen, z. B. „Größe“. */
698
+ label: string;
699
+ /**
700
+ * 1–30 Werte zu je 1–30 Zeichen, eindeutig ohne Gross/Klein, getrimmt und in
701
+ * Unicode-NFC gespeichert. Werte kommen nur dazu (`addAttributeValues`), nie weg.
702
+ */
703
+ values: string[];
704
+ }
705
+ /**
706
+ * Vorgaben einer Gruppe: sie fuellen bei der **Anlage** einer Variante die
707
+ * Felder, die die Variante nicht selbst nennt. Ein spaeteres Aendern der
708
+ * Vorgaben aendert keine bestehende Variante (dafuer `updateArticle`).
709
+ * Ein Feld ohne Vorgabe fehlt.
710
+ */
711
+ export interface VariantGroupDefaults {
712
+ unitPriceCents?: number;
713
+ vatRate?: number;
714
+ unit?: string;
715
+ groupId?: string;
716
+ /** Ohne Vorgabe gilt wie bei `createArticle` `false` (dann nicht reservierbar). */
717
+ stockTracked?: boolean;
718
+ }
719
+ /** Eine Variante in der Liste ihrer Gruppe. */
720
+ export interface VariantGroupMember {
721
+ articleId: string;
722
+ /** Je Merkmal ein Wert, Schluessel nach Codepunkt sortiert. */
723
+ variantAttributes: Record<string, string>;
724
+ }
725
+ /**
726
+ * Eine Variantengruppe, wie `getVariantGroup`, `listVariantGroups`, die
727
+ * schreibenden Gruppenaufrufe und die Ereignisse `variant_group.*` sie senden.
728
+ */
729
+ export interface VariantGroup {
730
+ id: string;
731
+ /** 1–100 Zeichen; Standardname einer Variante: „<Gruppe> <Wert1> <Wert2>“. */
732
+ name: string | null;
733
+ /** 1–3 Merkmale in der Reihenfolge der Gruppe (sie bestimmt den Standardnamen). */
734
+ attributes: VariantAttribute[];
735
+ defaults: VariantGroupDefaults;
736
+ /** `false` = stillgelegt: alle Varianten stillgelegt, kein `addVariant`, endgueltig. */
737
+ active: boolean;
738
+ /**
739
+ * Die aktiven Varianten einer aktiven Gruppe; eine einzeln stillgelegte
740
+ * Variante faellt heraus (ihre Kombination ist dann wieder frei). Beim
741
+ * Stilllegen der Gruppe wird die Liste eingefroren. Die Artikel selbst
742
+ * liest `listArticles({ variantGroupId })`.
743
+ */
744
+ variants: VariantGroupMember[];
745
+ createdAt: string | null;
746
+ updatedAt: string | null;
747
+ }
748
+ /** Vorgaben in einer Anfrage. Bei der Anlage heisst `null` „nicht angegeben“, bei einer Aenderung „leeren“. */
749
+ export interface VariantGroupDefaultsInput {
750
+ unitPriceCents?: number | null;
751
+ vatRate?: number | null;
752
+ unit?: string | null;
753
+ /** Artikelgruppe; unbekannt = `group_not_found` (bei einer Variante mit `field: 'defaults.groupId'`). */
754
+ groupId?: string | null;
755
+ stockTracked?: boolean | null;
756
+ }
757
+ /**
758
+ * Eine neue Variante: ihre Merkmalswerte und die Felder eines Artikels wie bei
759
+ * `createArticle`. Was fehlt (oder `null` ist), fuellen die Vorgaben der
760
+ * Gruppe; ohne `name` heisst sie „<Gruppe> <Wert1> <Wert2>“ in
761
+ * Merkmalsreihenfolge. Mit `ean` wird sie ein Fremdartikel, sonst vergibt der
762
+ * Server den naechsten eigenen Code.
763
+ */
764
+ export interface VariantInput extends Omit<ArticleInput, 'name'> {
765
+ /**
766
+ * Jedes Merkmal der Gruppe genau einmal, Wert exakt aus der Werteliste
767
+ * (Gross/Klein und Leerraum werden nicht angeglichen), sonst
768
+ * `invalid_variant_attributes` mit `field`.
769
+ */
770
+ variantAttributes: Record<string, string>;
771
+ /** 1–200 Zeichen; ohne Angabe der Standardname. */
772
+ name?: string | null;
773
+ }
774
+ /**
775
+ * Legt eine Variantengruppe an, mit `createMatrix: true` samt allen
776
+ * Kombinationen (hoechstens 100) oder mit den genannten `variants[]`
777
+ * (hoechstens 100), nie beides. Ohne beides entsteht die Gruppe ohne Variante.
778
+ * Die Antwort traegt die Gruppe mit `variants[]` (Kennungen und Merkmale),
779
+ * nicht die Artikel.
780
+ */
781
+ export interface CreateVariantGroupRequest {
782
+ idempotencyKey: string;
783
+ /** 1–100 Zeichen. */
784
+ name: string;
785
+ /** 1–3 Merkmale; ihre Reihenfolge bestimmt Standardnamen und Matrix (das erste laeuft aussen). */
786
+ attributes: VariantAttribute[];
787
+ defaults?: VariantGroupDefaultsInput | null;
788
+ /** `true`: alle Kombinationen der Werte als Varianten. Schliesst `variants` aus. */
789
+ createMatrix?: boolean;
790
+ variants?: VariantInput[];
791
+ }
792
+ /**
793
+ * Aendert eine aktive Gruppe: nur die genannten Felder, mindestens eines.
794
+ * `defaults` ist ein Teil-Update (`null` je Feld leert es, `defaults: null`
795
+ * alle). `addAttributeValues` haengt Werte an bestehende Merkmale an und
796
+ * uebergeht still, was es schon gibt (auch in anderer Gross-/Kleinschreibung):
797
+ * der Shop darf immer alle seine Werte senden. Werte entfernen und Merkmale
798
+ * ergaenzen gibt es nicht.
799
+ *
800
+ * `active: false` legt die Gruppe und alle ihre Varianten still, steht allein
801
+ * und ist endgueltig (`true` gibt es nicht). Eine stillgelegte Gruppe ergibt
802
+ * bei jeder anderen Aenderung `variant_group_inactive`.
803
+ */
804
+ export interface UpdateVariantGroupRequest {
805
+ idempotencyKey: string;
806
+ variantGroupId: string;
807
+ name?: string;
808
+ defaults?: VariantGroupDefaultsInput | null;
809
+ /** `{ groesse: ['XL'] }`: hoechstens 30 Werte je Merkmal danach. */
810
+ addAttributeValues?: Record<string, string[]>;
811
+ active?: false;
812
+ }
813
+ /** Legt eine Variante in einer aktiven Gruppe an. Antwort: der Artikel wie `createArticle`. */
814
+ export interface AddVariantRequest extends VariantInput {
815
+ idempotencyKey: string;
816
+ variantGroupId: string;
817
+ }
818
+ export interface VariantGroupListQuery {
819
+ active?: boolean;
820
+ /**
821
+ * Nur Gruppen, die seitdem geaendert wurden (inklusive). Die Liste ist nach
822
+ * `updatedAt` aufsteigend sortiert, gleiche Zeit nach Kennung.
823
+ */
824
+ updatedSince?: string | Date;
825
+ /** 1–200, Vorgabe des Servers 50. */
826
+ limit?: number;
827
+ cursor?: string;
828
+ }
829
+ export interface VariantGroupPage {
830
+ variantGroups: VariantGroup[];
831
+ /** `null` = letzte Seite. */
832
+ nextCursor: string | null;
833
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Variantengruppen der Lager-API (Backend Stufe 5c): Gruppe anlegen (mit
3
+ * Matrix oder genannten Varianten), aendern oder stilllegen, eine Variante
4
+ * ergaenzen, Gruppen lesen.
5
+ *
6
+ * Eine Variante ist ein gewoehnlicher Artikel mit `variantGroupId` und
7
+ * `variantAttributes`; gelesen, gebucht und reserviert wird sie wie jeder
8
+ * Artikel. Die Gruppenantworten tragen nur die Kennungen der Varianten, die
9
+ * Artikel selbst liefert `listArticles({ variantGroupId })`.
10
+ *
11
+ * Wie in `schreiben.ts` geht die Anfrage flach hinaus, genau mit den Feldern,
12
+ * die der Aufrufer nennt (`undefined` faellt weg, `null` bleibt).
13
+ *
14
+ * **Vor dem Senden geprueft wird nur, was ohne Netz sicher falsch ist:**
15
+ * - `idempotencyKey` fehlt, ist leer oder laenger als 120 Zeichen (die drei
16
+ * schreibenden Aufrufe);
17
+ * - `variantGroupId` fehlt oder ist leer;
18
+ * - `createMatrix: true` zusammen mit `variants` (schliessen sich aus);
19
+ * - `variants` ist keine Liste, ein Eintrag kein Objekt, `variantAttributes`
20
+ * einer Variante fehlt oder ist kein Objekt;
21
+ * - ein Preis, eine Menge oder ein Einkaufspreis (auch in `defaults`) ist
22
+ * keine Ganzzahl;
23
+ * - eine Aenderung nennt kein Feld, `active` ist nicht `false` oder steht
24
+ * nicht allein, `addAttributeValues` ist kein Objekt.
25
+ * Die Grenzen (Merkmale, Werte, Matrix, aktive Varianten) prueft der Server:
26
+ * er darf sie anheben, ohne dass diese Paketversion dann falsch abweist.
27
+ *
28
+ * **Wiederholen** wie bei jedem Schreiben: nach `outcome: 'unknown'` denselben
29
+ * Aufruf mit **demselben** `idempotencyKey`; er wirkt genau einmal und liefert
30
+ * die gespeicherte Antwort. Ein neuer Schluessel legte die Gruppe ein zweites
31
+ * Mal an. Ein abgebrochenes Stilllegen vollendet jede Wiederholung von
32
+ * `updateVariantGroup({ active: false })`, auch mit neuem Schluessel.
33
+ */
34
+ import type { InternerTransport } from '../client/aufrufe.js';
35
+ import type { AddVariantRequest, Article, CreateVariantGroupRequest, UpdateVariantGroupRequest, VariantGroup, VariantGroupListQuery, VariantGroupPage } from './typen.js';
36
+ /**
37
+ * Legt eine Variantengruppe an: mit `createMatrix: true` alle Kombinationen der
38
+ * Werte (hoechstens 100), sonst die genannten `variants[]` (hoechstens 100),
39
+ * ohne beides nur die Gruppe. Jede Variante entsteht als Artikel mit den
40
+ * Feldern wie bei `createArticle`; was sie nicht nennt, fuellen die Vorgaben.
41
+ * Antwort: die Gruppe mit `variants[]` (Kennung und Merkmale je Variante).
42
+ *
43
+ * Braucht die Anlage mehr Schreibvorgaenge, als in einen Vorgang passen,
44
+ * kommt `too_many_positions` mit `field` (`variants` bzw. `createMatrix`) und
45
+ * nichts ist geschrieben: weniger Varianten senden, den Rest per [addVariant].
46
+ */
47
+ export declare function createVariantGroup(transport: InternerTransport, request: CreateVariantGroupRequest): Promise<VariantGroup>;
48
+ /**
49
+ * Aendert eine aktive Gruppe (Name, Vorgaben, neue Werte) oder legt sie mit
50
+ * `active: false` still: die Gruppe und alle ihre Varianten, endgueltig. Die
51
+ * Antwort kommt erst, wenn alle Varianten stillgelegt sind. Bestehende
52
+ * Varianten aendern Name und Vorgaben nicht (dafuer `updateArticle`).
53
+ */
54
+ export declare function updateVariantGroup(transport: InternerTransport, request: UpdateVariantGroupRequest): Promise<VariantGroup>;
55
+ /**
56
+ * Legt eine Variante in einer aktiven Gruppe an. Antwort: der Artikel wie
57
+ * `createArticle`. Gibt es die Kombination schon, kommt
58
+ * `variant_already_exists` mit `articleId` der bestehenden Variante; nach dem
59
+ * Stilllegen einer Variante ist ihre Kombination wieder frei.
60
+ */
61
+ export declare function addVariant(transport: InternerTransport, request: AddVariantRequest): Promise<Article>;
62
+ /** Eine Variantengruppe mit ihren aktiven Varianten (eingefroren, wenn stillgelegt). */
63
+ export declare function getVariantGroup(transport: InternerTransport, variantGroupId: string): Promise<VariantGroup>;
64
+ /** Variantengruppen nach `updatedAt` aufsteigend; Filter `active` und `updatedSince` (inklusive). */
65
+ export declare function listVariantGroups(transport: InternerTransport, query?: VariantGroupListQuery): Promise<VariantGroupPage>;
66
+ /** Alle Variantengruppen der Abfrage, Seite fuer Seite ueber `nextCursor`. */
67
+ export declare function iterateVariantGroups(transport: InternerTransport, query?: VariantGroupListQuery): AsyncGenerator<VariantGroup, void, undefined>;
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Variantengruppen der Lager-API (Backend Stufe 5c): Gruppe anlegen (mit
3
+ * Matrix oder genannten Varianten), aendern oder stilllegen, eine Variante
4
+ * ergaenzen, Gruppen lesen.
5
+ *
6
+ * Eine Variante ist ein gewoehnlicher Artikel mit `variantGroupId` und
7
+ * `variantAttributes`; gelesen, gebucht und reserviert wird sie wie jeder
8
+ * Artikel. Die Gruppenantworten tragen nur die Kennungen der Varianten, die
9
+ * Artikel selbst liefert `listArticles({ variantGroupId })`.
10
+ *
11
+ * Wie in `schreiben.ts` geht die Anfrage flach hinaus, genau mit den Feldern,
12
+ * die der Aufrufer nennt (`undefined` faellt weg, `null` bleibt).
13
+ *
14
+ * **Vor dem Senden geprueft wird nur, was ohne Netz sicher falsch ist:**
15
+ * - `idempotencyKey` fehlt, ist leer oder laenger als 120 Zeichen (die drei
16
+ * schreibenden Aufrufe);
17
+ * - `variantGroupId` fehlt oder ist leer;
18
+ * - `createMatrix: true` zusammen mit `variants` (schliessen sich aus);
19
+ * - `variants` ist keine Liste, ein Eintrag kein Objekt, `variantAttributes`
20
+ * einer Variante fehlt oder ist kein Objekt;
21
+ * - ein Preis, eine Menge oder ein Einkaufspreis (auch in `defaults`) ist
22
+ * keine Ganzzahl;
23
+ * - eine Aenderung nennt kein Feld, `active` ist nicht `false` oder steht
24
+ * nicht allein, `addAttributeValues` ist kein Objekt.
25
+ * Die Grenzen (Merkmale, Werte, Matrix, aktive Varianten) prueft der Server:
26
+ * er darf sie anheben, ohne dass diese Paketversion dann falsch abweist.
27
+ *
28
+ * **Wiederholen** wie bei jedem Schreiben: nach `outcome: 'unknown'` denselben
29
+ * Aufruf mit **demselben** `idempotencyKey`; er wirkt genau einmal und liefert
30
+ * die gespeicherte Antwort. Ein neuer Schluessel legte die Gruppe ein zweites
31
+ * Mal an. Ein abgebrochenes Stilllegen vollendet jede Wiederholung von
32
+ * `updateVariantGroup({ active: false })`, auch mit neuem Schluessel.
33
+ */
34
+ import { abfrage, anfragefehler, kennung, seitenweise } from './endpunkte.js';
35
+ import { liste, naechsterCursor, objekt, variantengruppe } from './lesen.js';
36
+ import { anfrage, artikelAus, artikelZahlen, ganz, schluessel } from './schreiben.js';
37
+ const istObjekt = (w) => w !== null && typeof w === 'object' && !Array.isArray(w);
38
+ /** Vorgaben: nur der Preis ist eine Zahl mit Skala (Cent); `null` leert bzw. heisst „nicht angegeben“. */
39
+ function vorgabenZahlen(name, w) {
40
+ if (w === undefined || w === null)
41
+ return;
42
+ if (!istObjekt(w))
43
+ throw anfragefehler(name, 'defaults muss ein Objekt oder null sein');
44
+ ganz(name, 'defaults.unitPriceCents', w.unitPriceCents, { leerbar: true });
45
+ }
46
+ /** Eine Variante der Anfrage: Merkmale als Objekt, Zahlen ganzzahlig. */
47
+ function variante(name, w, praefix) {
48
+ const stelle = praefix ? praefix.slice(0, -1) : 'Anfrage';
49
+ if (!istObjekt(w))
50
+ throw anfragefehler(name, `${stelle} muss ein Objekt sein`);
51
+ if (!istObjekt(w.variantAttributes)) {
52
+ throw anfragefehler(name, `${praefix}variantAttributes fehlt oder ist kein Objekt { merkmal: wert }`);
53
+ }
54
+ artikelZahlen(name, w, praefix);
55
+ }
56
+ const gruppeAus = (name, daten) => variantengruppe({ name, pfad: 'variantGroup' }, objekt(daten)?.variantGroup);
57
+ /**
58
+ * Legt eine Variantengruppe an: mit `createMatrix: true` alle Kombinationen der
59
+ * Werte (hoechstens 100), sonst die genannten `variants[]` (hoechstens 100),
60
+ * ohne beides nur die Gruppe. Jede Variante entsteht als Artikel mit den
61
+ * Feldern wie bei `createArticle`; was sie nicht nennt, fuellen die Vorgaben.
62
+ * Antwort: die Gruppe mit `variants[]` (Kennung und Merkmale je Variante).
63
+ *
64
+ * Braucht die Anlage mehr Schreibvorgaenge, als in einen Vorgang passen,
65
+ * kommt `too_many_positions` mit `field` (`variants` bzw. `createMatrix`) und
66
+ * nichts ist geschrieben: weniger Varianten senden, den Rest per [addVariant].
67
+ */
68
+ export async function createVariantGroup(transport, request) {
69
+ const name = 'createVariantGroup';
70
+ const p = anfrage(name, request);
71
+ schluessel(name, p, { pflicht: true });
72
+ if (p.createMatrix === true && p.variants !== null && p.variants !== undefined) {
73
+ throw anfragefehler(name, 'createMatrix und variants schliessen sich aus: entweder alle Kombinationen oder die genannten Varianten');
74
+ }
75
+ vorgabenZahlen(name, p.defaults);
76
+ if (p.variants !== null && p.variants !== undefined) {
77
+ if (!Array.isArray(p.variants))
78
+ throw anfragefehler(name, 'variants muss eine Liste sein');
79
+ p.variants.forEach((x, i) => variante(name, x, `variants[${i}].`));
80
+ }
81
+ return gruppeAus(name, await transport(name, p));
82
+ }
83
+ /**
84
+ * Aendert eine aktive Gruppe (Name, Vorgaben, neue Werte) oder legt sie mit
85
+ * `active: false` still: die Gruppe und alle ihre Varianten, endgueltig. Die
86
+ * Antwort kommt erst, wenn alle Varianten stillgelegt sind. Bestehende
87
+ * Varianten aendern Name und Vorgaben nicht (dafuer `updateArticle`).
88
+ */
89
+ export async function updateVariantGroup(transport, request) {
90
+ const name = 'updateVariantGroup';
91
+ const p = anfrage(name, request);
92
+ schluessel(name, p, { pflicht: true });
93
+ kennung(name, 'variantGroupId', p.variantGroupId);
94
+ const aenderungen = ['name', 'defaults', 'addAttributeValues'].filter((k) => p[k] !== undefined);
95
+ if (p.active !== undefined) {
96
+ if (p.active !== false)
97
+ throw anfragefehler(name, 'active kennt nur false (stilllegen); eine stillgelegte Gruppe bleibt stillgelegt');
98
+ if (aenderungen.length)
99
+ throw anfragefehler(name, 'active: false steht allein, ohne weitere Aenderung');
100
+ }
101
+ else if (!aenderungen.length) {
102
+ throw anfragefehler(name, 'die Aenderung nennt kein Feld');
103
+ }
104
+ vorgabenZahlen(name, p.defaults);
105
+ if (p.addAttributeValues !== undefined && !istObjekt(p.addAttributeValues)) {
106
+ throw anfragefehler(name, 'addAttributeValues muss ein Objekt { merkmal: [werte] } sein');
107
+ }
108
+ return gruppeAus(name, await transport(name, p));
109
+ }
110
+ /**
111
+ * Legt eine Variante in einer aktiven Gruppe an. Antwort: der Artikel wie
112
+ * `createArticle`. Gibt es die Kombination schon, kommt
113
+ * `variant_already_exists` mit `articleId` der bestehenden Variante; nach dem
114
+ * Stilllegen einer Variante ist ihre Kombination wieder frei.
115
+ */
116
+ export async function addVariant(transport, request) {
117
+ const name = 'addVariant';
118
+ const p = anfrage(name, request);
119
+ schluessel(name, p, { pflicht: true });
120
+ kennung(name, 'variantGroupId', p.variantGroupId);
121
+ variante(name, p, '');
122
+ return artikelAus(name, await transport(name, p));
123
+ }
124
+ /** Eine Variantengruppe mit ihren aktiven Varianten (eingefroren, wenn stillgelegt). */
125
+ export async function getVariantGroup(transport, variantGroupId) {
126
+ const name = 'getVariantGroup';
127
+ return gruppeAus(name, await transport(name, { variantGroupId: kennung(name, 'variantGroupId', variantGroupId) }));
128
+ }
129
+ /** Variantengruppen nach `updatedAt` aufsteigend; Filter `active` und `updatedSince` (inklusive). */
130
+ export async function listVariantGroups(transport, query) {
131
+ const name = 'listVariantGroups';
132
+ const daten = await transport(name, abfrage(name, query));
133
+ return { variantGroups: liste(name, daten, 'variantGroups', variantengruppe), nextCursor: naechsterCursor(name, daten) };
134
+ }
135
+ /** Alle Variantengruppen der Abfrage, Seite fuer Seite ueber `nextCursor`. */
136
+ export function iterateVariantGroups(transport, query) {
137
+ const { cursor, ...rest } = query ?? {};
138
+ return seitenweise('listVariantGroups', cursor, async (c) => {
139
+ const s = await listVariantGroups(transport, { ...rest, cursor: c });
140
+ return { eintraege: s.variantGroups, nextCursor: s.nextCursor };
141
+ });
142
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Der Vertrag der Lager-API (Backend Stufe 5a lesen, 5b schreiben und
3
- * reservieren) als Daten: Endpunkte, Wertkataloge, Ereignisse, Fehler- und
3
+ * reservieren, 5c Varianten) als Daten: Endpunkte, Wertkataloge, Ereignisse, Fehler- und
4
4
  * Hinweiscodes, englisch wie am Draht `/v3`.
5
5
  *
6
6
  * Quelle ist der Vertrags-Export des Backends (`fixtures/v3/v3-vokabular.json`):
@@ -11,8 +11,8 @@
11
11
  * und `warningCodes.inventory`. `test/inventory.test.ts` haelt jede Liste
12
12
  * deckungsgleich mit dieser Datei; nichts hier wird geraten.
13
13
  */
14
- /** Die 27 Endpunkte (14 aus 5a, 13 aus 5b), in der Reihenfolge von `endpoints.public`. */
15
- export declare const INVENTORY_ENDPOINTS: readonly ["getArticle", "listArticles", "lookupArticleByCode", "listLocations", "getStock", "listStock", "listStockMovements", "createWebhook", "updateWebhook", "deleteWebhook", "listWebhooks", "sendWebhookTest", "rotateWebhookSecret", "listWebhookDeliveries", "createArticle", "updateArticle", "deactivateArticle", "receiveGoods", "transferStock", "recordStockLoss", "changeStockCondition", "reverseStockMovement", "createReservation", "extendReservation", "releaseReservation", "getReservation", "listReservations"];
14
+ /** Die 32 Endpunkte (14 aus 5a, 13 aus 5b, 5 aus 5c), in der Reihenfolge von `endpoints.public`. */
15
+ export declare const INVENTORY_ENDPOINTS: readonly ["getArticle", "listArticles", "lookupArticleByCode", "listLocations", "getStock", "listStock", "listStockMovements", "createWebhook", "updateWebhook", "deleteWebhook", "listWebhooks", "sendWebhookTest", "rotateWebhookSecret", "listWebhookDeliveries", "createArticle", "updateArticle", "deactivateArticle", "receiveGoods", "transferStock", "recordStockLoss", "changeStockCondition", "reverseStockMovement", "createReservation", "extendReservation", "releaseReservation", "getReservation", "listReservations", "createVariantGroup", "updateVariantGroup", "getVariantGroup", "listVariantGroups", "addVariant"];
16
16
  export type InventoryEndpoint = (typeof INVENTORY_ENDPOINTS)[number];
17
17
  /** Art eines Standorts (Katalog `STANDORT_TYP`). */
18
18
  export declare const LOCATION_TYPES: readonly ["warehouse", "store", "vehicle", "other"];
@@ -52,8 +52,12 @@ export type WebhookDeliveryStatus = (typeof WEBHOOK_DELIVERY_STATUSES)[number];
52
52
  * wie `getReservation`, mit dem Status danach: `reservation.released` und
53
53
  * `reservation.redeemed` kommen bei jeder wirksamen Freigabe bzw. Einloesung,
54
54
  * auch einer teilweisen (dann bleibt der Status `active`).
55
+ * `variant_group.created` und `variant_group.updated` (seit 1.6.0) tragen die
56
+ * Variantengruppe wie `getVariantGroup`; `updated` kommt nur bei einer aussen
57
+ * sichtbaren Aenderung (neuer Wert, neue oder stillgelegte Variante, Name,
58
+ * Vorgaben, Stilllegen der Gruppe).
55
59
  */
56
- export declare const INVENTORY_WEBHOOK_EVENTS: readonly ["stock.changed", "stock.below_minimum", "article.created", "article.updated", "article.deactivated", "reservation.expired", "reservation.released", "reservation.redeemed"];
60
+ export declare const INVENTORY_WEBHOOK_EVENTS: readonly ["stock.changed", "stock.below_minimum", "article.created", "article.updated", "article.deactivated", "reservation.expired", "reservation.released", "reservation.redeemed", "variant_group.created", "variant_group.updated"];
57
61
  export type InventoryWebhookEventType = (typeof INVENTORY_WEBHOOK_EVENTS)[number];
58
62
  /**
59
63
  * Die Felder der Huelle jeder Zustellung, in der Reihenfolge am Draht. Statt
@@ -81,8 +85,21 @@ export declare const INVENTORY_LIST_LIMIT_MAX = 200;
81
85
  * [inventoryShortfalls]), `code_taken` und `external_id_taken` (mit `field` und
82
86
  * `articleId` des Artikels, dem der Code gehoert), `stock_kind_locked`,
83
87
  * `reservation_not_found`, `reservation_not_active` …
88
+ *
89
+ * Seit 1.6.0 dahinter die Codes der Variantengruppen: `variant_group_not_found`
90
+ * (unbekannte Kennung), `variant_already_exists` (die Kombination gibt es in der
91
+ * Gruppe schon, dann mit `articleId` der bestehenden Variante, oder sie steht
92
+ * zweimal in `variants[]`; jeweils mit `field`),
93
+ * `invalid_variant_attributes` (ein Merkmal fehlt, ist unbekannt oder sein Wert
94
+ * steht nicht in der Werteliste; `field` und `errors[]`),
95
+ * `variant_group_inactive` (stillgelegte Gruppe: kein `addVariant`, keine
96
+ * Aenderung ausser erneutem Stilllegen) und `variant_limit` (mehr als
97
+ * [VARIANT_GROUP_ACTIVE_MAX] aktive Varianten je Gruppe). Wiederverwendet:
98
+ * `too_many_positions` traegt bei Varianten `field` (`variants`,
99
+ * `createMatrix` bzw. `externalIds` bei `addVariant`): die Anfrage braeuchte
100
+ * mehr Schreibvorgaenge, als in einen Vorgang passen; geschrieben wurde nichts.
84
101
  */
85
- export declare const INVENTORY_ERROR_CODES: readonly ["validation", "invalid_cursor", "article_not_found", "webhook_not_found", "webhook_limit", "invalid_webhook_url", "event_not_subscribed", "webhook_inactive", "inventory_api_not_enabled", "module_inactive", "rate_limited", "server_error", "idempotency_key_required", "idempotency_conflict", "location_not_found", "location_inactive", "invalid_location", "invalid_locations", "invalid_transfer", "operation_not_found", "already_reversed", "reversal_not_possible", "reversal_not_supported", "exceeds_stock", "no_positions", "too_many_positions", "invalid_step", "invalid_quantity", "invalid_amount", "invalid_price", "negative_value", "invalid_reason", "note_required", "withdrawal_type_required", "invalid_method", "invalid_stock_kind", "invalid_minimum", "invalid_dimensions", "weight_missing", "invalid_landed_cost", "invalid_distribution", "landed_costs_mismatch", "return_totals_mismatch", "lot_not_found", "invalid_serial", "serial_required", "serial_not_allowed", "serial_already_exists", "serial_not_in_stock", "code_taken", "external_id_taken", "group_not_found", "revenue_group_not_found", "stock_kind_locked", "article_inactive", "invalid_position", "invalid_condition", "reason_required", "insufficient_available", "reservation_not_found", "reservation_not_active"];
102
+ export declare const INVENTORY_ERROR_CODES: readonly ["validation", "invalid_cursor", "article_not_found", "webhook_not_found", "webhook_limit", "invalid_webhook_url", "event_not_subscribed", "webhook_inactive", "inventory_api_not_enabled", "module_inactive", "rate_limited", "server_error", "idempotency_key_required", "idempotency_conflict", "location_not_found", "location_inactive", "invalid_location", "invalid_locations", "invalid_transfer", "operation_not_found", "already_reversed", "reversal_not_possible", "reversal_not_supported", "exceeds_stock", "no_positions", "too_many_positions", "invalid_step", "invalid_quantity", "invalid_amount", "invalid_price", "negative_value", "invalid_reason", "note_required", "withdrawal_type_required", "invalid_method", "invalid_stock_kind", "invalid_minimum", "invalid_dimensions", "weight_missing", "invalid_landed_cost", "invalid_distribution", "landed_costs_mismatch", "return_totals_mismatch", "lot_not_found", "invalid_serial", "serial_required", "serial_not_allowed", "serial_already_exists", "serial_not_in_stock", "code_taken", "external_id_taken", "group_not_found", "revenue_group_not_found", "stock_kind_locked", "article_inactive", "invalid_position", "invalid_condition", "reason_required", "insufficient_available", "reservation_not_found", "reservation_not_active", "variant_group_not_found", "variant_already_exists", "invalid_variant_attributes", "variant_group_inactive", "variant_limit"];
86
103
  export type InventoryErrorCode = (typeof INVENTORY_ERROR_CODES)[number];
87
104
  /**
88
105
  * Codes, die Anmeldung und Rand auf jedem Lager-Aufruf erzeugen koennen,
@@ -134,3 +151,21 @@ export declare const INVENTORY_IDEMPOTENCY_KEY_MAX = 120;
134
151
  /** Kuerzeste und laengste Haltedauer einer Reservierung in Minuten (`expiresInMinutes`, 30 Tage). */
135
152
  export declare const RESERVATION_MINUTES_MIN = 5;
136
153
  export declare const RESERVATION_MINUTES_MAX = 43200;
154
+ /**
155
+ * Grenzen einer Variantengruppe, wie das Backend sie prueft. Das Paket prueft
156
+ * sie **nicht** vor dem Senden: der Server darf sie anheben, ohne dass eine
157
+ * aeltere Paketversion dann faelschlich abweist. Wer darueber liegt, bekommt
158
+ * `validation` (Merkmale, Werte, Matrix, `variants[]`) bzw. `variant_limit`.
159
+ *
160
+ * - [VARIANT_ATTRIBUTES_MAX] Merkmale je Gruppe (Schluessel `^[a-z0-9_]{1,32}$`,
161
+ * eindeutig; `__…__` ist reserviert),
162
+ * - [VARIANT_VALUES_MAX] Werte je Merkmal (je 1–30 Zeichen, eindeutig ohne
163
+ * Gross/Klein),
164
+ * - [VARIANT_MATRIX_MAX] Kombinationen bei `createMatrix: true` und hoechstens
165
+ * so viele Eintraege in `variants[]` je Anfrage,
166
+ * - [VARIANT_GROUP_ACTIVE_MAX] aktive Varianten je Gruppe.
167
+ */
168
+ export declare const VARIANT_ATTRIBUTES_MAX = 3;
169
+ export declare const VARIANT_VALUES_MAX = 30;
170
+ export declare const VARIANT_MATRIX_MAX = 100;
171
+ export declare const VARIANT_GROUP_ACTIVE_MAX = 250;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Der Vertrag der Lager-API (Backend Stufe 5a lesen, 5b schreiben und
3
- * reservieren) als Daten: Endpunkte, Wertkataloge, Ereignisse, Fehler- und
3
+ * reservieren, 5c Varianten) als Daten: Endpunkte, Wertkataloge, Ereignisse, Fehler- und
4
4
  * Hinweiscodes, englisch wie am Draht `/v3`.
5
5
  *
6
6
  * Quelle ist der Vertrags-Export des Backends (`fixtures/v3/v3-vokabular.json`):
@@ -11,7 +11,7 @@
11
11
  * und `warningCodes.inventory`. `test/inventory.test.ts` haelt jede Liste
12
12
  * deckungsgleich mit dieser Datei; nichts hier wird geraten.
13
13
  */
14
- /** Die 27 Endpunkte (14 aus 5a, 13 aus 5b), in der Reihenfolge von `endpoints.public`. */
14
+ /** Die 32 Endpunkte (14 aus 5a, 13 aus 5b, 5 aus 5c), in der Reihenfolge von `endpoints.public`. */
15
15
  export const INVENTORY_ENDPOINTS = [
16
16
  'getArticle',
17
17
  'listArticles',
@@ -40,6 +40,11 @@ export const INVENTORY_ENDPOINTS = [
40
40
  'releaseReservation',
41
41
  'getReservation',
42
42
  'listReservations',
43
+ 'createVariantGroup',
44
+ 'updateVariantGroup',
45
+ 'getVariantGroup',
46
+ 'listVariantGroups',
47
+ 'addVariant',
43
48
  ];
44
49
  /** Art eines Standorts (Katalog `STANDORT_TYP`). */
45
50
  export const LOCATION_TYPES = ['warehouse', 'store', 'vehicle', 'other'];
@@ -113,6 +118,10 @@ export const WEBHOOK_DELIVERY_STATUSES = ['delivered', 'pending', 'failed', 'dro
113
118
  * wie `getReservation`, mit dem Status danach: `reservation.released` und
114
119
  * `reservation.redeemed` kommen bei jeder wirksamen Freigabe bzw. Einloesung,
115
120
  * auch einer teilweisen (dann bleibt der Status `active`).
121
+ * `variant_group.created` und `variant_group.updated` (seit 1.6.0) tragen die
122
+ * Variantengruppe wie `getVariantGroup`; `updated` kommt nur bei einer aussen
123
+ * sichtbaren Aenderung (neuer Wert, neue oder stillgelegte Variante, Name,
124
+ * Vorgaben, Stilllegen der Gruppe).
116
125
  */
117
126
  export const INVENTORY_WEBHOOK_EVENTS = [
118
127
  'stock.changed',
@@ -123,6 +132,8 @@ export const INVENTORY_WEBHOOK_EVENTS = [
123
132
  'reservation.expired',
124
133
  'reservation.released',
125
134
  'reservation.redeemed',
135
+ 'variant_group.created',
136
+ 'variant_group.updated',
126
137
  ];
127
138
  /**
128
139
  * Die Felder der Huelle jeder Zustellung, in der Reihenfolge am Draht. Statt
@@ -150,6 +161,19 @@ export const INVENTORY_LIST_LIMIT_MAX = 200;
150
161
  * [inventoryShortfalls]), `code_taken` und `external_id_taken` (mit `field` und
151
162
  * `articleId` des Artikels, dem der Code gehoert), `stock_kind_locked`,
152
163
  * `reservation_not_found`, `reservation_not_active` …
164
+ *
165
+ * Seit 1.6.0 dahinter die Codes der Variantengruppen: `variant_group_not_found`
166
+ * (unbekannte Kennung), `variant_already_exists` (die Kombination gibt es in der
167
+ * Gruppe schon, dann mit `articleId` der bestehenden Variante, oder sie steht
168
+ * zweimal in `variants[]`; jeweils mit `field`),
169
+ * `invalid_variant_attributes` (ein Merkmal fehlt, ist unbekannt oder sein Wert
170
+ * steht nicht in der Werteliste; `field` und `errors[]`),
171
+ * `variant_group_inactive` (stillgelegte Gruppe: kein `addVariant`, keine
172
+ * Aenderung ausser erneutem Stilllegen) und `variant_limit` (mehr als
173
+ * [VARIANT_GROUP_ACTIVE_MAX] aktive Varianten je Gruppe). Wiederverwendet:
174
+ * `too_many_positions` traegt bei Varianten `field` (`variants`,
175
+ * `createMatrix` bzw. `externalIds` bei `addVariant`): die Anfrage braeuchte
176
+ * mehr Schreibvorgaenge, als in einen Vorgang passen; geschrieben wurde nichts.
153
177
  */
154
178
  export const INVENTORY_ERROR_CODES = [
155
179
  'validation',
@@ -213,6 +237,11 @@ export const INVENTORY_ERROR_CODES = [
213
237
  'insufficient_available',
214
238
  'reservation_not_found',
215
239
  'reservation_not_active',
240
+ 'variant_group_not_found',
241
+ 'variant_already_exists',
242
+ 'invalid_variant_attributes',
243
+ 'variant_group_inactive',
244
+ 'variant_limit',
216
245
  ];
217
246
  /**
218
247
  * Codes, die Anmeldung und Rand auf jedem Lager-Aufruf erzeugen koennen,
@@ -286,3 +315,22 @@ export const INVENTORY_IDEMPOTENCY_KEY_MAX = 120;
286
315
  /** Kuerzeste und laengste Haltedauer einer Reservierung in Minuten (`expiresInMinutes`, 30 Tage). */
287
316
  export const RESERVATION_MINUTES_MIN = 5;
288
317
  export const RESERVATION_MINUTES_MAX = 43_200;
318
+ // ---- Varianten (Backend Stufe 5c, seit 1.6.0) -----------------------------------
319
+ /**
320
+ * Grenzen einer Variantengruppe, wie das Backend sie prueft. Das Paket prueft
321
+ * sie **nicht** vor dem Senden: der Server darf sie anheben, ohne dass eine
322
+ * aeltere Paketversion dann faelschlich abweist. Wer darueber liegt, bekommt
323
+ * `validation` (Merkmale, Werte, Matrix, `variants[]`) bzw. `variant_limit`.
324
+ *
325
+ * - [VARIANT_ATTRIBUTES_MAX] Merkmale je Gruppe (Schluessel `^[a-z0-9_]{1,32}$`,
326
+ * eindeutig; `__…__` ist reserviert),
327
+ * - [VARIANT_VALUES_MAX] Werte je Merkmal (je 1–30 Zeichen, eindeutig ohne
328
+ * Gross/Klein),
329
+ * - [VARIANT_MATRIX_MAX] Kombinationen bei `createMatrix: true` und hoechstens
330
+ * so viele Eintraege in `variants[]` je Anfrage,
331
+ * - [VARIANT_GROUP_ACTIVE_MAX] aktive Varianten je Gruppe.
332
+ */
333
+ export const VARIANT_ATTRIBUTES_MAX = 3;
334
+ export const VARIANT_VALUES_MAX = 30;
335
+ export const VARIANT_MATRIX_MAX = 100;
336
+ export const VARIANT_GROUP_ACTIVE_MAX = 250;
@@ -39,10 +39,13 @@ export declare function verifyInventoryWebhookSignature(secret: string | readonl
39
39
  * Liest eine Zustellung als typisiertes Ereignis. Vorher die Signatur pruefen
40
40
  * ([verifyInventoryWebhookSignature]).
41
41
  *
42
- * - Ein Ereignis, das diese Paketversion nicht kennt (etwa `variant_group.*`
43
- * einer spaeteren Stufe), ergibt `null`: mit 2xx antworten und uebergehen.
42
+ * - Ein Ereignis, das diese Paketversion nicht kennt (eines einer spaeteren
43
+ * Stufe), ergibt `null`: mit 2xx antworten und uebergehen.
44
44
  * - `reservation.expired|released|redeemed` tragen die Reservierung wie
45
45
  * `getReservation`, mit dem Status nach dem Vorgang (seit 1.5.0).
46
+ * - `variant_group.created|updated` tragen die Gruppe wie `getVariantGroup`
47
+ * (seit 1.6.0). Zwei Zustellungen koennen sich ueberholen: den Stand nur
48
+ * uebernehmen, wenn `data.updatedAt` neuer ist als der gespeicherte.
46
49
  * - Ein Rumpf, der keine Huelle ist, oder eine Bruchzahl in einer Menge wirft
47
50
  * `KasseneckValidationError` (`scope: 'response'`).
48
51
  *
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import { KasseneckValidationError } from '../client/errors.js';
17
17
  import { verifyWebhookSignature as pruefeSignatur } from '../partner/webhook-signatur.js';
18
- import { artikel, bestandGeaendert, objekt, reservierung, unterMindestbestand } from './lesen.js';
18
+ import { artikel, bestandGeaendert, objekt, reservierung, unterMindestbestand, variantengruppe } from './lesen.js';
19
19
  import { INVENTORY_WEBHOOK_EVENTS } from './vertrag.js';
20
20
  export { WEBHOOK_SIGNATURE_HEADER, WEBHOOK_EVENT_HEADER, WEBHOOK_DELIVERY_HEADER, WEBHOOK_TOLERANCE_SEC, } from '../partner/webhook-signatur.js';
21
21
  /**
@@ -56,10 +56,13 @@ function kaputt(grund) {
56
56
  * Liest eine Zustellung als typisiertes Ereignis. Vorher die Signatur pruefen
57
57
  * ([verifyInventoryWebhookSignature]).
58
58
  *
59
- * - Ein Ereignis, das diese Paketversion nicht kennt (etwa `variant_group.*`
60
- * einer spaeteren Stufe), ergibt `null`: mit 2xx antworten und uebergehen.
59
+ * - Ein Ereignis, das diese Paketversion nicht kennt (eines einer spaeteren
60
+ * Stufe), ergibt `null`: mit 2xx antworten und uebergehen.
61
61
  * - `reservation.expired|released|redeemed` tragen die Reservierung wie
62
62
  * `getReservation`, mit dem Status nach dem Vorgang (seit 1.5.0).
63
+ * - `variant_group.created|updated` tragen die Gruppe wie `getVariantGroup`
64
+ * (seit 1.6.0). Zwei Zustellungen koennen sich ueberholen: den Stand nur
65
+ * uebernehmen, wenn `data.updatedAt` neuer ist als der gespeicherte.
63
66
  * - Ein Rumpf, der keine Huelle ist, oder eine Bruchzahl in einer Menge wirft
64
67
  * `KasseneckValidationError` (`scope: 'response'`).
65
68
  *
@@ -101,6 +104,9 @@ export function parseInventoryWebhookEvent(rawBody) {
101
104
  case 'reservation.released':
102
105
  case 'reservation.redeemed':
103
106
  return { ...huelle, type: huelle.type, data: reservierung(ort, data) };
107
+ case 'variant_group.created':
108
+ case 'variant_group.updated':
109
+ return { ...huelle, type: huelle.type, data: variantengruppe(ort, data) };
104
110
  default:
105
111
  return { ...huelle, type: huelle.type, data: artikel(ort, data) };
106
112
  }
@@ -12,6 +12,12 @@
12
12
  * **Nicht automatisch wiederholen.** Wer nach einem Zeitlimit erneut
13
13
  * ausstellt, tut das mit **demselben** `idempotencyKey`: dann kommt die schon
14
14
  * ausgestellte Rechnung zurueck (`replayed: true`) statt einer zweiten.
15
+ * Jeder Aufruf mit Wirkung (ausstellen, stornieren, gutschreiben, Zahlung
16
+ * nachtragen, Kunde anlegen oder aendern) meldet nach Zeitlimit, Netzfehler,
17
+ * HTTP 5xx oder unlesbarer Antwort `outcome: 'unknown'`: er kann gewirkt
18
+ * haben. Mit Schluessel denselben Schluessel erneut senden, ohne Schluessel
19
+ * (`updateCustomer`, `createCustomer` ohne) erst nachlesen. Lesen und der
20
+ * Probelauf (`previewInvoice`) bleiben `'rejected'`.
15
21
  *
16
22
  * Nach dem Senden wird nichts hart gecastet: fehlt ein zugesagtes Feld, wirft
17
23
  * der Aufruf `KasseneckValidationError` mit `scope:'response'`.