@kreiseck/kasseneck-api 0.14.0 → 0.15.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 (55) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +65 -0
  3. package/dist/cjs/client/aufrufe.d.ts +1 -1
  4. package/dist/cjs/client/aufrufe.js +11 -0
  5. package/dist/cjs/rechnung/api.d.ts +43 -0
  6. package/dist/cjs/rechnung/api.js +35 -0
  7. package/dist/cjs/rechnung/auth.d.ts +21 -0
  8. package/dist/cjs/rechnung/auth.js +36 -0
  9. package/dist/cjs/rechnung/endpunkte.d.ts +48 -0
  10. package/dist/cjs/rechnung/endpunkte.js +129 -0
  11. package/dist/cjs/rechnung/fehler.d.ts +21 -0
  12. package/dist/cjs/rechnung/fehler.js +44 -0
  13. package/dist/cjs/rechnung/index.d.ts +18 -0
  14. package/dist/cjs/rechnung/index.js +52 -0
  15. package/dist/cjs/rechnung/typen.d.ts +224 -0
  16. package/dist/cjs/rechnung/typen.js +9 -0
  17. package/dist/cjs/rechnung/vertrag.d.ts +98 -0
  18. package/dist/cjs/rechnung/vertrag.js +191 -0
  19. package/dist/esm/client/aufrufe.d.ts +1 -1
  20. package/dist/esm/client/aufrufe.js +11 -0
  21. package/dist/esm/rechnung/api.d.ts +43 -0
  22. package/dist/esm/rechnung/api.js +32 -0
  23. package/dist/esm/rechnung/auth.d.ts +21 -0
  24. package/dist/esm/rechnung/auth.js +33 -0
  25. package/dist/esm/rechnung/endpunkte.d.ts +48 -0
  26. package/dist/esm/rechnung/endpunkte.js +116 -0
  27. package/dist/esm/rechnung/fehler.d.ts +21 -0
  28. package/dist/esm/rechnung/fehler.js +39 -0
  29. package/dist/esm/rechnung/index.d.ts +18 -0
  30. package/dist/esm/rechnung/index.js +17 -0
  31. package/dist/esm/rechnung/typen.d.ts +224 -0
  32. package/dist/esm/rechnung/typen.js +8 -0
  33. package/dist/esm/rechnung/vertrag.d.ts +98 -0
  34. package/dist/esm/rechnung/vertrag.js +188 -0
  35. package/fixtures/hobex-hps-codes.json +1 -1
  36. package/fixtures/kasse-texte.json +1 -1
  37. package/fixtures/oberflaeche.json +87 -1
  38. package/fixtures/rechnung-api-beispiele/credit-fehler-grund.json +24 -0
  39. package/fixtures/rechnung-api-beispiele/credit-ok.json +20 -0
  40. package/fixtures/rechnung-api-beispiele/customer-fehler-uid.json +25 -0
  41. package/fixtures/rechnung-api-beispiele/customer-get-fehler-beide.json +15 -0
  42. package/fixtures/rechnung-api-beispiele/customer-ok.json +20 -0
  43. package/fixtures/rechnung-api-beispiele/customer-search-fehler-leer.json +14 -0
  44. package/fixtures/rechnung-api-beispiele/issue-brutto-20.json +27 -0
  45. package/fixtures/rechnung-api-beispiele/issue-fehler-cent.json +26 -0
  46. package/fixtures/rechnung-api-beispiele/issue-fehler-menge.json +26 -0
  47. package/fixtures/rechnung-api-beispiele/issue-fehler-negativ.json +26 -0
  48. package/fixtures/rechnung-api-beispiele/issue-fehler-satz.json +26 -0
  49. package/fixtures/rechnung-api-beispiele/issue-fehler-unbekannt.json +27 -0
  50. package/fixtures/rechnung-api-beispiele/issue-gemischt.json +33 -0
  51. package/fixtures/rechnung-api-beispiele/issue-kleinunternehmer.json +27 -0
  52. package/fixtures/rechnung-api-beispiele/issue-netto-20.json +28 -0
  53. package/fixtures/rechnung-api-beispiele/issue-rabatt.json +28 -0
  54. package/fixtures/rechnung-api.schema.json +672 -0
  55. package/package.json +12 -1
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Der Vertrag der Rechnungs-API — als Daten, nicht als Prosa.
3
+ *
4
+ * Aus dieser Datei entstehen drei Dinge, damit sie nicht auseinanderlaufen
5
+ * koennen:
6
+ *
7
+ * 1. `fixtures/rechnung-api.schema.json` (`npm run fixtures:rechnung`) — das
8
+ * Backend liest es aus dem vendorierten Paket und vergleicht es in beide
9
+ * Richtungen mit seiner eigenen Pruefung; der Dart-Zwilling zieht es byteweise.
10
+ * 2. Die Listen unter `rechnung` in `fixtures/oberflaeche.json` (Codes, Gruende,
11
+ * Enums) — ueber denselben Namensraum-Scan wie der Partner-Teil.
12
+ * 3. Die TypeScript-Typen in `typen.ts`.
13
+ *
14
+ * Nach aussen spricht die Schnittstelle Englisch: Feldnamen, Codes, Gruende.
15
+ * Deutsch bleibt, was ein Mensch liest (`message`, der Aufdruck eines Grundes).
16
+ *
17
+ * Beschrieben wird die Anfrage. Was der Server daraus macht — Rechnungsdatum,
18
+ * Nummer, Summen — ist bewusst **nicht** setzbar.
19
+ */
20
+ export const RECHNUNG_VERTRAG_VERSION = 1;
21
+ export const RECHNUNG_AUFRUFE = [
22
+ 'createCustomer',
23
+ 'getCustomer',
24
+ 'updateCustomer',
25
+ 'searchCustomers',
26
+ 'issueInvoice',
27
+ 'cancelInvoice',
28
+ 'createCreditNote',
29
+ 'getInvoice',
30
+ 'listInvoices',
31
+ 'getInvoicePdf',
32
+ 'getInvoiceXml',
33
+ ];
34
+ /**
35
+ * Stabile Fehlercodes. Das Fremdsystem verzweigt am Code, der Text darf sich
36
+ * aendern. `validation` traegt zusaetzlich `errors: [{ field, message }]`.
37
+ */
38
+ export const INVOICE_ERROR_CODES = [
39
+ 'validation',
40
+ 'idempotency_conflict',
41
+ 'module_inactive',
42
+ 'customer_not_found',
43
+ 'customer_exists',
44
+ 'short_code_taken',
45
+ 'short_code_immutable',
46
+ 'recipient_required',
47
+ 'invoice_requirements_missing',
48
+ 'invoice_not_found',
49
+ 'invoice_ambiguous',
50
+ 'not_cancellable',
51
+ 'partial_credit_exists',
52
+ 'credit_exceeds_invoice',
53
+ 'einvoice_incomplete',
54
+ ];
55
+ /** Gruende einer Gutschrift. Der Server druckt den deutschen Anzeigetext. */
56
+ export const CREDIT_NOTE_REASONS = [
57
+ 'cancellation',
58
+ 'price_reduction',
59
+ 'return',
60
+ 'incorrect_invoice',
61
+ 'other',
62
+ ];
63
+ export const TAX_SCHEMES = ['normal', 'smallBusiness', 'reverseCharge', 'igLieferung', 'exportThirdCountry'];
64
+ export const PRICE_MODES = ['net', 'gross'];
65
+ export const VAT_RATES = [0, 10, 13, 20];
66
+ export const CUSTOMER_TYPES = ['private', 'company'];
67
+ export const INVOICE_LIST_STATUS = ['final', 'paid', 'cancelled', 'open', 'overdue'];
68
+ export const DOC_TYPES = ['RE', 'GU'];
69
+ export const EINVOICE_FORMATS = ['ubl', 'cii'];
70
+ const text = (max, pflicht = false, extra = {}) => ({ typ: 'string', pflicht, max, ...(pflicht && extra.min === undefined ? { min: 1 } : {}), ...extra });
71
+ const idempotencyKey = (pflicht) => ({ typ: 'string', pflicht, min: 1, max: 120 });
72
+ const id = { typ: 'string', pflicht: false, min: 1, max: 128 };
73
+ const idPflicht = { typ: 'string', pflicht: true, min: 1, max: 128 };
74
+ const datum = (pflicht = false) => ({ typ: 'string', pflicht, min: 10, max: 10, format: 'date' });
75
+ const limit = { typ: 'integer', pflicht: false, min: 1, max: 100 };
76
+ const cursor = { typ: 'string', pflicht: false, min: 1, max: 500 };
77
+ /** Kunde, wie das Fremdsystem ihn schickt. `vatId` ist die UID-Nummer. */
78
+ export const KUNDE_FELDER = Object.freeze({
79
+ type: { typ: 'enum', pflicht: true, werte: CUSTOMER_TYPES },
80
+ name: text(200, true),
81
+ legalForm: text(40),
82
+ email: text(254, false, { format: 'email' }),
83
+ phone: text(40, false, { format: 'phone' }),
84
+ street: text(200),
85
+ houseNumber: text(20),
86
+ zip: text(10),
87
+ city: text(100),
88
+ country: text(2, true, { min: 2, format: 'country' }),
89
+ vatId: text(20, false, { format: 'vatId' }),
90
+ shortCode: text(8, false, { format: 'shortCode' }),
91
+ isAuthority: { typ: 'boolean', pflicht: false },
92
+ note: text(1000),
93
+ externalId: { typ: 'string', pflicht: false, min: 1, max: 120 },
94
+ });
95
+ /** Beim Aendern ist jedes Kundenfeld optional. */
96
+ const KUNDE_PATCH = Object.freeze(Object.fromEntries(Object.entries(KUNDE_FELDER).map(([name, feld]) => [name, { ...feld, pflicht: false }])));
97
+ /** Eine Rechnungs- oder Gutschriftsposition. Preise in ganzen Cent. */
98
+ export const POSITION_FELDER = Object.freeze({
99
+ description: text(300, true),
100
+ subtitle: text(1000),
101
+ quantity: { typ: 'number', pflicht: true, min: 0, exklusivMin: true, max: 1_000_000, nachkomma: 3 },
102
+ unit: text(20),
103
+ unitPriceCents: { typ: 'integer', pflicht: true, min: 0, max: 100_000_000 },
104
+ vatRate: { typ: 'enum', pflicht: true, werte: VAT_RATES },
105
+ discountPct: { typ: 'number', pflicht: false, min: 0, max: 100, nachkomma: 2 },
106
+ });
107
+ const positionen = { typ: 'list', pflicht: true, min: 1, max: 500, eintrag: { typ: 'object', pflicht: true, felder: POSITION_FELDER } };
108
+ export const RECHNUNG_ANFRAGEN = Object.freeze({
109
+ createCustomer: {
110
+ customer: { typ: 'object', pflicht: true, felder: KUNDE_FELDER },
111
+ idempotencyKey: idempotencyKey(false),
112
+ },
113
+ getCustomer: {
114
+ customerId: id,
115
+ externalId: { typ: 'string', pflicht: false, min: 1, max: 120 },
116
+ },
117
+ updateCustomer: {
118
+ customerId: idPflicht,
119
+ customer: { typ: 'object', pflicht: true, felder: KUNDE_PATCH },
120
+ },
121
+ searchCustomers: {
122
+ externalId: { typ: 'string', pflicht: false, min: 1, max: 120 },
123
+ vatId: text(20),
124
+ email: text(254),
125
+ name: text(200),
126
+ limit,
127
+ cursor,
128
+ },
129
+ issueInvoice: {
130
+ idempotencyKey: idempotencyKey(true),
131
+ customerId: id,
132
+ taxScheme: { typ: 'enum', pflicht: true, werte: TAX_SCHEMES },
133
+ priceMode: { typ: 'enum', pflicht: true, werte: PRICE_MODES },
134
+ serviceStart: datum(true),
135
+ serviceEnd: datum(),
136
+ paymentTermDays: { typ: 'integer', pflicht: false, min: 0, max: 365 },
137
+ orderReference: text(200),
138
+ intro: text(2000),
139
+ note: text(2000),
140
+ paymentReference: text(140),
141
+ girocode: { typ: 'boolean', pflicht: false },
142
+ tracking: { typ: 'boolean', pflicht: false },
143
+ items: positionen,
144
+ metadata: { typ: 'map', pflicht: false, maxSchluessel: 20, schluesselMuster: '^[a-zA-Z0-9_]{1,40}$', wertMax: 500 },
145
+ },
146
+ cancelInvoice: {
147
+ idempotencyKey: idempotencyKey(true),
148
+ invoiceId: idPflicht,
149
+ reason: { typ: 'enum', pflicht: true, werte: CREDIT_NOTE_REASONS },
150
+ note: text(2000),
151
+ },
152
+ createCreditNote: {
153
+ idempotencyKey: idempotencyKey(true),
154
+ invoiceId: idPflicht,
155
+ reason: { typ: 'enum', pflicht: true, werte: CREDIT_NOTE_REASONS },
156
+ note: text(2000),
157
+ items: positionen,
158
+ },
159
+ getInvoice: {
160
+ invoiceId: id,
161
+ number: { typ: 'string', pflicht: false, min: 1, max: 100 },
162
+ },
163
+ listInvoices: {
164
+ from: datum(),
165
+ to: datum(),
166
+ status: { typ: 'enum', pflicht: false, werte: INVOICE_LIST_STATUS },
167
+ docType: { typ: 'enum', pflicht: false, werte: DOC_TYPES },
168
+ customerId: id,
169
+ limit,
170
+ cursor,
171
+ },
172
+ getInvoicePdf: {
173
+ invoiceId: idPflicht,
174
+ },
175
+ getInvoiceXml: {
176
+ invoiceId: idPflicht,
177
+ format: { typ: 'enum', pflicht: false, werte: EINVOICE_FORMATS },
178
+ },
179
+ });
180
+ /** Genau eines dieser Felder muss gesetzt sein (je Aufruf, je Gruppe). */
181
+ export const RECHNUNG_GENAU_EINS = Object.freeze({
182
+ getCustomer: [['customerId', 'externalId']],
183
+ getInvoice: [['invoiceId', 'number']],
184
+ });
185
+ /** Mindestens eines dieser Felder muss gesetzt sein (je Aufruf, je Gruppe). */
186
+ export const RECHNUNG_MINDESTENS_EINS = Object.freeze({
187
+ searchCustomers: [['externalId', 'vatId', 'email', 'name']],
188
+ });
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.14.0",
2
+ "version": "0.15.0",
3
3
  "gemessenAn": {
4
4
  "tid": "3600335",
5
5
  "hpsVersion": "1.10.0",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.14.0",
2
+ "version": "0.15.0",
3
3
  "meldungen": {
4
4
  "netz.keine_verbindung": {
5
5
  "text": "Keine Verbindung zum Server. Bitte die Internetverbindung prüfen und erneut versuchen."
@@ -1,8 +1,11 @@
1
1
  {
2
- "version": "0.14.0",
2
+ "version": "0.15.0",
3
3
  "aufrufe": [
4
4
  "activateCashregister",
5
+ "cancelInvoice",
5
6
  "cancelReceipt",
7
+ "createCreditNote",
8
+ "createCustomer",
6
9
  "createCustomerCashregister",
7
10
  "createPartnerCustomer",
8
11
  "checkPartnerCustomerEmail",
@@ -16,9 +19,13 @@
16
19
  "endRegisterSession",
17
20
  "financeWebService",
18
21
  "generateFullReceiptId",
22
+ "getCustomer",
19
23
  "getCustomerCredentials",
20
24
  "getCustomerSignatureStatus",
21
25
  "getFirstReceiptDate",
26
+ "getInvoice",
27
+ "getInvoicePdf",
28
+ "getInvoiceXml",
22
29
  "getKasseSettings",
23
30
  "getPartnerCustomer",
24
31
  "getPartnerInfo",
@@ -26,7 +33,9 @@
26
33
  "getReceipt",
27
34
  "hobexPayApi",
28
35
  "hobexRefundApi",
36
+ "issueInvoice",
29
37
  "listCustomerCashregisters",
38
+ "listInvoices",
30
39
  "listMyArticleGroups",
31
40
  "listMyArticles",
32
41
  "listMyCashregisters",
@@ -43,6 +52,7 @@
43
52
  "registerUserLogin",
44
53
  "renewRegisterSession",
45
54
  "requestCustomerSignature",
55
+ "searchCustomers",
46
56
  "sendPartnerCustomerFonLink",
47
57
  "sendPartnerWebhookTest",
48
58
  "sendReceiptEmail",
@@ -51,6 +61,7 @@
51
61
  "stripeCaptureIntent",
52
62
  "unpairRegisterDevice",
53
63
  "rotatePartnerWebhookSecret",
64
+ "updateCustomer",
54
65
  "updatePartnerWebhook"
55
66
  ],
56
67
  "enums": {
@@ -348,5 +359,80 @@
348
359
  "test",
349
360
  "data"
350
361
  ]
362
+ },
363
+ "rechnung": {
364
+ "creditNoteReasons": [
365
+ "cancellation",
366
+ "price_reduction",
367
+ "return",
368
+ "incorrect_invoice",
369
+ "other"
370
+ ],
371
+ "customerTypes": [
372
+ "private",
373
+ "company"
374
+ ],
375
+ "docTypes": [
376
+ "RE",
377
+ "GU"
378
+ ],
379
+ "einvoiceFormats": [
380
+ "ubl",
381
+ "cii"
382
+ ],
383
+ "invoiceErrorCodes": [
384
+ "validation",
385
+ "idempotency_conflict",
386
+ "module_inactive",
387
+ "customer_not_found",
388
+ "customer_exists",
389
+ "short_code_taken",
390
+ "short_code_immutable",
391
+ "recipient_required",
392
+ "invoice_requirements_missing",
393
+ "invoice_not_found",
394
+ "invoice_ambiguous",
395
+ "not_cancellable",
396
+ "partial_credit_exists",
397
+ "credit_exceeds_invoice",
398
+ "einvoice_incomplete"
399
+ ],
400
+ "invoiceListStatus": [
401
+ "final",
402
+ "paid",
403
+ "cancelled",
404
+ "open",
405
+ "overdue"
406
+ ],
407
+ "priceModes": [
408
+ "net",
409
+ "gross"
410
+ ],
411
+ "rechnungAufrufe": [
412
+ "createCustomer",
413
+ "getCustomer",
414
+ "updateCustomer",
415
+ "searchCustomers",
416
+ "issueInvoice",
417
+ "cancelInvoice",
418
+ "createCreditNote",
419
+ "getInvoice",
420
+ "listInvoices",
421
+ "getInvoicePdf",
422
+ "getInvoiceXml"
423
+ ],
424
+ "taxSchemes": [
425
+ "normal",
426
+ "smallBusiness",
427
+ "reverseCharge",
428
+ "igLieferung",
429
+ "exportThirdCountry"
430
+ ],
431
+ "vatRates": [
432
+ 0,
433
+ 10,
434
+ 13,
435
+ 20
436
+ ]
351
437
  }
352
438
  }
@@ -0,0 +1,24 @@
1
+ {
2
+ "aufruf": "createCreditNote",
3
+ "beschreibung": "Unbekannter Grund",
4
+ "anfrage": {
5
+ "idempotencyKey": "bsp-12",
6
+ "invoiceId": "rechnung_beispiel",
7
+ "reason": "storno",
8
+ "items": [
9
+ {
10
+ "description": "Nachlass",
11
+ "quantity": 1,
12
+ "unitPriceCents": 5000,
13
+ "vatRate": 20
14
+ }
15
+ ]
16
+ },
17
+ "erwartet": {
18
+ "ok": false,
19
+ "code": "validation",
20
+ "fields": [
21
+ "reason"
22
+ ]
23
+ }
24
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "aufruf": "createCreditNote",
3
+ "beschreibung": "Teilgutschrift als Preisnachlass",
4
+ "anfrage": {
5
+ "idempotencyKey": "bsp-11",
6
+ "invoiceId": "rechnung_beispiel",
7
+ "reason": "price_reduction",
8
+ "items": [
9
+ {
10
+ "description": "Nachlass Beratung",
11
+ "quantity": 1,
12
+ "unitPriceCents": 5000,
13
+ "vatRate": 20
14
+ }
15
+ ]
16
+ },
17
+ "erwartet": {
18
+ "ok": true
19
+ }
20
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "aufruf": "createCustomer",
3
+ "beschreibung": "UID-Nummer im falschen Format",
4
+ "anfrage": {
5
+ "customer": {
6
+ "type": "company",
7
+ "name": "Café Muster GmbH",
8
+ "street": "Hauptplatz",
9
+ "houseNumber": "3",
10
+ "zip": "1010",
11
+ "city": "Wien",
12
+ "country": "AT",
13
+ "email": "rechnung@cafe-muster.example",
14
+ "externalId": "shop-4711",
15
+ "vatId": "ATU1"
16
+ }
17
+ },
18
+ "erwartet": {
19
+ "ok": false,
20
+ "code": "validation",
21
+ "fields": [
22
+ "customer.vatId"
23
+ ]
24
+ }
25
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "aufruf": "getCustomer",
3
+ "beschreibung": "Genau eine Kennung angeben",
4
+ "anfrage": {
5
+ "customerId": "kunde_beispiel",
6
+ "externalId": "shop-4711"
7
+ },
8
+ "erwartet": {
9
+ "ok": false,
10
+ "code": "validation",
11
+ "fields": [
12
+ "customerId"
13
+ ]
14
+ }
15
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "aufruf": "createCustomer",
3
+ "beschreibung": "Firmenkunde mit Kennung aus dem Shop",
4
+ "anfrage": {
5
+ "customer": {
6
+ "type": "company",
7
+ "name": "Café Muster GmbH",
8
+ "street": "Hauptplatz",
9
+ "houseNumber": "3",
10
+ "zip": "1010",
11
+ "city": "Wien",
12
+ "country": "AT",
13
+ "email": "rechnung@cafe-muster.example",
14
+ "externalId": "shop-4711"
15
+ }
16
+ },
17
+ "erwartet": {
18
+ "ok": true
19
+ }
20
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "aufruf": "searchCustomers",
3
+ "beschreibung": "Suche ohne Suchbegriff",
4
+ "anfrage": {
5
+ "limit": 10
6
+ },
7
+ "erwartet": {
8
+ "ok": false,
9
+ "code": "validation",
10
+ "fields": [
11
+ "externalId"
12
+ ]
13
+ }
14
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "aufruf": "issueInvoice",
3
+ "beschreibung": "Bruttopreis: der Server rechnet die USt heraus",
4
+ "anfrage": {
5
+ "idempotencyKey": "bsp-2",
6
+ "customerId": "kunde_beispiel",
7
+ "taxScheme": "normal",
8
+ "priceMode": "gross",
9
+ "serviceStart": "2026-09-14",
10
+ "items": [
11
+ {
12
+ "description": "Frühstück",
13
+ "quantity": 1,
14
+ "unitPriceCents": 1200,
15
+ "vatRate": 20
16
+ }
17
+ ]
18
+ },
19
+ "erwartet": {
20
+ "ok": true,
21
+ "totals": {
22
+ "netCents": 1000,
23
+ "vatCents": 200,
24
+ "grossCents": 1200
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "aufruf": "issueInvoice",
3
+ "beschreibung": "Beträge in ganzen Cent",
4
+ "anfrage": {
5
+ "idempotencyKey": "bsp-9",
6
+ "customerId": "kunde_beispiel",
7
+ "taxScheme": "normal",
8
+ "priceMode": "net",
9
+ "serviceStart": "2026-09-14",
10
+ "items": [
11
+ {
12
+ "description": "Beratung",
13
+ "quantity": 1,
14
+ "unitPriceCents": 12.5,
15
+ "vatRate": 20
16
+ }
17
+ ]
18
+ },
19
+ "erwartet": {
20
+ "ok": false,
21
+ "code": "validation",
22
+ "fields": [
23
+ "items[0].unitPriceCents"
24
+ ]
25
+ }
26
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "aufruf": "issueInvoice",
3
+ "beschreibung": "Menge null",
4
+ "anfrage": {
5
+ "idempotencyKey": "bsp-10",
6
+ "customerId": "kunde_beispiel",
7
+ "taxScheme": "normal",
8
+ "priceMode": "net",
9
+ "serviceStart": "2026-09-14",
10
+ "items": [
11
+ {
12
+ "description": "Beratung",
13
+ "quantity": 0,
14
+ "unitPriceCents": 5000,
15
+ "vatRate": 20
16
+ }
17
+ ]
18
+ },
19
+ "erwartet": {
20
+ "ok": false,
21
+ "code": "validation",
22
+ "fields": [
23
+ "items[0].quantity"
24
+ ]
25
+ }
26
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "aufruf": "issueInvoice",
3
+ "beschreibung": "Negativer Preis gehört in eine Gutschrift",
4
+ "anfrage": {
5
+ "idempotencyKey": "bsp-7",
6
+ "customerId": "kunde_beispiel",
7
+ "taxScheme": "normal",
8
+ "priceMode": "net",
9
+ "serviceStart": "2026-09-14",
10
+ "items": [
11
+ {
12
+ "description": "Nachlass",
13
+ "quantity": 1,
14
+ "unitPriceCents": -1,
15
+ "vatRate": 20
16
+ }
17
+ ]
18
+ },
19
+ "erwartet": {
20
+ "ok": false,
21
+ "code": "validation",
22
+ "fields": [
23
+ "items[0].unitPriceCents"
24
+ ]
25
+ }
26
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "aufruf": "issueInvoice",
3
+ "beschreibung": "Steuerfreies Schema mit USt-Satz",
4
+ "anfrage": {
5
+ "idempotencyKey": "bsp-6",
6
+ "customerId": "kunde_beispiel",
7
+ "taxScheme": "smallBusiness",
8
+ "priceMode": "net",
9
+ "serviceStart": "2026-09-14",
10
+ "items": [
11
+ {
12
+ "description": "Reparatur",
13
+ "quantity": 1,
14
+ "unitPriceCents": 5000,
15
+ "vatRate": 20
16
+ }
17
+ ]
18
+ },
19
+ "erwartet": {
20
+ "ok": false,
21
+ "code": "validation",
22
+ "fields": [
23
+ "items[0].vatRate"
24
+ ]
25
+ }
26
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "aufruf": "issueInvoice",
3
+ "beschreibung": "Die Nummer vergibt der Server",
4
+ "anfrage": {
5
+ "idempotencyKey": "bsp-8",
6
+ "customerId": "kunde_beispiel",
7
+ "taxScheme": "normal",
8
+ "priceMode": "net",
9
+ "serviceStart": "2026-09-14",
10
+ "items": [
11
+ {
12
+ "description": "Beratung",
13
+ "quantity": 1,
14
+ "unitPriceCents": 5000,
15
+ "vatRate": 20
16
+ }
17
+ ],
18
+ "number": "2026-0001"
19
+ },
20
+ "erwartet": {
21
+ "ok": false,
22
+ "code": "validation",
23
+ "fields": [
24
+ "number"
25
+ ]
26
+ }
27
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "aufruf": "issueInvoice",
3
+ "beschreibung": "Zwei Steuersätze auf einer Rechnung",
4
+ "anfrage": {
5
+ "idempotencyKey": "bsp-4",
6
+ "customerId": "kunde_beispiel",
7
+ "taxScheme": "normal",
8
+ "priceMode": "net",
9
+ "serviceStart": "2026-09-14",
10
+ "items": [
11
+ {
12
+ "description": "Beratung",
13
+ "quantity": 1,
14
+ "unitPriceCents": 10000,
15
+ "vatRate": 20
16
+ },
17
+ {
18
+ "description": "Buch",
19
+ "quantity": 1,
20
+ "unitPriceCents": 5000,
21
+ "vatRate": 10
22
+ }
23
+ ]
24
+ },
25
+ "erwartet": {
26
+ "ok": true,
27
+ "totals": {
28
+ "netCents": 15000,
29
+ "vatCents": 2500,
30
+ "grossCents": 17500
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "aufruf": "issueInvoice",
3
+ "beschreibung": "Kleinunternehmer: USt-Satz 0",
4
+ "anfrage": {
5
+ "idempotencyKey": "bsp-5",
6
+ "customerId": "kunde_beispiel",
7
+ "taxScheme": "smallBusiness",
8
+ "priceMode": "net",
9
+ "serviceStart": "2026-09-14",
10
+ "items": [
11
+ {
12
+ "description": "Reparatur",
13
+ "quantity": 1,
14
+ "unitPriceCents": 5000,
15
+ "vatRate": 0
16
+ }
17
+ ]
18
+ },
19
+ "erwartet": {
20
+ "ok": true,
21
+ "totals": {
22
+ "netCents": 5000,
23
+ "vatCents": 0,
24
+ "grossCents": 5000
25
+ }
26
+ }
27
+ }