@kreiseck/kasseneck-api 0.20.0 → 0.22.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 (39) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/README.md +37 -2
  3. package/dist/cjs/client/errors.d.ts +0 -1
  4. package/dist/cjs/client/errors.js +24 -1
  5. package/dist/cjs/rechnung/api.d.ts +3 -1
  6. package/dist/cjs/rechnung/api.js +1 -0
  7. package/dist/cjs/rechnung/endpunkte.d.ts +12 -1
  8. package/dist/cjs/rechnung/endpunkte.js +56 -3
  9. package/dist/cjs/rechnung/index.d.ts +4 -3
  10. package/dist/cjs/rechnung/index.js +7 -1
  11. package/dist/cjs/rechnung/summen.d.ts +41 -0
  12. package/dist/cjs/rechnung/summen.js +81 -0
  13. package/dist/cjs/rechnung/texte.d.ts +19 -0
  14. package/dist/cjs/rechnung/texte.js +40 -0
  15. package/dist/cjs/rechnung/typen.d.ts +71 -9
  16. package/dist/cjs/rechnung/vertrag.d.ts +78 -3
  17. package/dist/cjs/rechnung/vertrag.js +82 -4
  18. package/dist/esm/client/errors.d.ts +0 -1
  19. package/dist/esm/client/errors.js +24 -1
  20. package/dist/esm/rechnung/api.d.ts +3 -1
  21. package/dist/esm/rechnung/api.js +2 -1
  22. package/dist/esm/rechnung/endpunkte.d.ts +12 -1
  23. package/dist/esm/rechnung/endpunkte.js +55 -3
  24. package/dist/esm/rechnung/index.d.ts +4 -3
  25. package/dist/esm/rechnung/index.js +3 -2
  26. package/dist/esm/rechnung/summen.d.ts +41 -0
  27. package/dist/esm/rechnung/summen.js +77 -0
  28. package/dist/esm/rechnung/texte.d.ts +19 -0
  29. package/dist/esm/rechnung/texte.js +40 -0
  30. package/dist/esm/rechnung/typen.d.ts +71 -9
  31. package/dist/esm/rechnung/vertrag.d.ts +78 -3
  32. package/dist/esm/rechnung/vertrag.js +81 -3
  33. package/fixtures/hobex-hps-codes.json +1 -1
  34. package/fixtures/kasse-texte.json +1 -1
  35. package/fixtures/oberflaeche.json +27 -4
  36. package/fixtures/rechnung-api.schema.json +42 -4
  37. package/fixtures/rechnung-summen.json +154 -0
  38. package/fixtures/rechnung-texte.json +39 -1
  39. package/package.json +1 -1
@@ -24,8 +24,12 @@ const DE = {
24
24
  'pdf.tabelle.ust': 'UST',
25
25
  'pdf.tabelle.einzelNetto': 'EINZEL NETTO',
26
26
  'pdf.tabelle.betragNetto': 'BETRAG NETTO',
27
+ 'pdf.tabelle.einzelBrutto': 'EINZEL BRUTTO',
28
+ 'pdf.tabelle.betragBrutto': 'BETRAG BRUTTO',
29
+ 'pdf.position.rabatt': 'abzüglich {prozent} % Rabatt',
27
30
  'pdf.summe.zwischensumme': 'Zwischensumme netto',
28
31
  'pdf.summe.umsatzsteuer': 'Umsatzsteuer {satz}%',
32
+ 'pdf.summe.darinUst': 'darin {satz}% USt von {netto} netto',
29
33
  'pdf.summe.gesamt.rechnung': 'Gesamtbetrag',
30
34
  'pdf.summe.gesamt.gutschrift': 'Gutschriftsbetrag',
31
35
  'steuer.kleinunternehmer': 'Gemäß § 6 Abs. 1 Z 27 UStG wird keine Umsatzsteuer verrechnet (Kleinunternehmer).',
@@ -41,6 +45,22 @@ const DE = {
41
45
  // Beide UID-Nummern: bei Reverse Charge § 11 Abs. 1a, bei der ig. Lieferung
42
46
  // Art. 11 Abs. 2 UStG.
43
47
  'steuer.uidZeile': 'UID Leistungserbringer: {verkaeufer} · UID Leistungsempfänger: {kaeufer}',
48
+ // Inlands-Reverse-Charge: je Grund ein Satz, der die Gesetzesstelle nennt —
49
+ // sie traegt den Hinweis nach § 11 Abs. 1a UStG.
50
+ 'steuer.rcGrund.construction': 'Bauleistung gemäß § 19 Abs. 1a UStG.',
51
+ 'steuer.rcGrund.scrap': 'Schrott und Abfallstoffe gemäß Schrott-Umsatzsteuerverordnung (BGBl. II Nr. 129/2007).',
52
+ 'steuer.rcGrund.mobile_devices': 'Mobilfunkgeräte bzw. integrierte Schaltkreise gemäß § 19 Abs. 1e lit. b UStG.',
53
+ 'steuer.rcGrund.it_devices': 'Laptops, Tablets bzw. Videospielkonsolen gemäß § 2 Z 1 Umsatzsteuerbetrugsbekämpfungsverordnung (BGBl. II Nr. 369/2013).',
54
+ 'steuer.rcGrund.metals': 'Metalle gemäß § 2 Z 4 Umsatzsteuerbetrugsbekämpfungsverordnung.',
55
+ 'steuer.rcGrund.emission_certificates': 'Treibhausgasemissionszertifikate gemäß § 19 Abs. 1e lit. a UStG.',
56
+ 'steuer.rcGrund.gas_electricity': 'Lieferung von Gas oder Elektrizität an einen Wiederverkäufer gemäß § 2 Z 2 Umsatzsteuerbetrugsbekämpfungsverordnung.',
57
+ 'steuer.rcGrund.energy_certificates': 'Gas- und Elektrizitätszertifikate gemäß § 2 Z 3 Umsatzsteuerbetrugsbekämpfungsverordnung.',
58
+ 'steuer.rcGrund.investment_gold': 'Steuerpflichtige Lieferung von Anlagegold gemäß § 2 Z 5 Umsatzsteuerbetrugsbekämpfungsverordnung.',
59
+ 'steuer.rcGrund.security_transfer': 'Lieferung von Sicherungs- bzw. Vorbehaltseigentum gemäß § 19 Abs. 1b UStG.',
60
+ 'steuer.rcGrund.foreign_supplier': 'Leistung eines nicht im Inland ansässigen Unternehmers gemäß § 19 Abs. 1 zweiter Satz UStG.',
61
+ 'steuer.domestic.text': 'Die Umsatzsteuer schuldet und entrichtet der Leistungsempfänger. Die Leistung ist nicht steuerfrei.',
62
+ 'steuer.outsideScope.titel': 'Nicht steuerbarer Umsatz. ',
63
+ 'steuer.outsideScope.text': 'Der Leistungsort liegt gemäß § 3a Abs. 6 UStG im Ansässigkeitsstaat des Leistungsempfängers; in Österreich fällt keine Umsatzsteuer an.',
44
64
  'pdf.zahlung.titel': 'ZAHLUNGSINFORMATIONEN',
45
65
  'pdf.zahlung.empfaenger': 'Empfänger',
46
66
  'pdf.zahlung.iban': 'IBAN',
@@ -90,6 +110,7 @@ const DE = {
90
110
  'einvoice.befreiung.reverseCharge': 'Steuerschuldnerschaft des Leistungsempfängers (Reverse Charge)',
91
111
  'einvoice.befreiung.kleinunternehmer': 'Steuerbefreit — Kleinunternehmer gemäß §6 Abs. 1 Z 27 UStG',
92
112
  'einvoice.befreiung.igLieferung': 'Steuerfreie innergemeinschaftliche Lieferung gemäß Art. 6 Abs. 1 UStG',
113
+ 'einvoice.befreiung.outsideScope': 'Nicht steuerbarer Umsatz — Leistungsort im Ausland (§ 3a Abs. 6 UStG)',
93
114
  'einvoice.befreiung.ausfuhr': 'Steuerfreie Ausfuhrlieferung gemäß §6 Abs. 1 Z 1 UStG',
94
115
  'einvoice.zahlbarBis': 'Zahlbar bis {datum}',
95
116
  'einheit.piece': 'Stk',
@@ -213,8 +234,12 @@ const EN = {
213
234
  'pdf.tabelle.ust': 'VAT',
214
235
  'pdf.tabelle.einzelNetto': 'UNIT NET',
215
236
  'pdf.tabelle.betragNetto': 'AMOUNT NET',
237
+ 'pdf.tabelle.einzelBrutto': 'UNIT GROSS',
238
+ 'pdf.tabelle.betragBrutto': 'AMOUNT GROSS',
239
+ 'pdf.position.rabatt': 'less {prozent}% discount',
216
240
  'pdf.summe.zwischensumme': 'Subtotal net',
217
241
  'pdf.summe.umsatzsteuer': 'VAT {satz}%',
242
+ 'pdf.summe.darinUst': 'incl. {satz}% VAT on {netto} net',
218
243
  'pdf.summe.gesamt.rechnung': 'Total',
219
244
  'pdf.summe.gesamt.gutschrift': 'Credit total',
220
245
  'steuer.kleinunternehmer': 'No VAT charged pursuant to § 6 (1) no. 27 UStG (small business exemption).',
@@ -224,6 +249,20 @@ const EN = {
224
249
  'steuer.reverseCharge.titel': 'Reverse charge – VAT liability of the recipient. ',
225
250
  'steuer.reverseCharge.text': 'VAT liability transferred pursuant to Art. 196 of VAT Directive 2006/112/EC (intra-Community service). The service is not VAT-exempt — the recipient owes and accounts for the VAT in their country.',
226
251
  'steuer.uidZeile': 'VAT ID supplier: {verkaeufer} · VAT ID recipient: {kaeufer}',
252
+ 'steuer.rcGrund.construction': 'Construction work pursuant to § 19 (1a) UStG.',
253
+ 'steuer.rcGrund.scrap': 'Scrap and waste materials pursuant to the Austrian scrap VAT regulation (BGBl. II No. 129/2007).',
254
+ 'steuer.rcGrund.mobile_devices': 'Mobile phones or integrated circuits pursuant to § 19 (1e) (b) UStG.',
255
+ 'steuer.rcGrund.it_devices': 'Laptops, tablets or games consoles pursuant to § 2 no. 1 of the Austrian VAT anti-fraud regulation (BGBl. II No. 369/2013).',
256
+ 'steuer.rcGrund.metals': 'Metals pursuant to § 2 no. 4 of the Austrian VAT anti-fraud regulation.',
257
+ 'steuer.rcGrund.emission_certificates': 'Greenhouse gas emission allowances pursuant to § 19 (1e) (a) UStG.',
258
+ 'steuer.rcGrund.gas_electricity': 'Supply of gas or electricity to a reseller pursuant to § 2 no. 2 of the Austrian VAT anti-fraud regulation.',
259
+ 'steuer.rcGrund.energy_certificates': 'Gas and electricity certificates pursuant to § 2 no. 3 of the Austrian VAT anti-fraud regulation.',
260
+ 'steuer.rcGrund.investment_gold': 'Taxable supply of investment gold pursuant to § 2 no. 5 of the Austrian VAT anti-fraud regulation.',
261
+ 'steuer.rcGrund.security_transfer': 'Supply of goods under a security or retention of title arrangement pursuant to § 19 (1b) UStG.',
262
+ 'steuer.rcGrund.foreign_supplier': 'Supply by a business not established in Austria pursuant to § 19 (1) second sentence UStG.',
263
+ 'steuer.domestic.text': 'The recipient owes and accounts for the VAT. The supply is not VAT-exempt.',
264
+ 'steuer.outsideScope.titel': 'Outside the scope of Austrian VAT. ',
265
+ 'steuer.outsideScope.text': 'The place of supply is the recipient\'s country pursuant to § 3a (6) UStG; no Austrian VAT applies.',
227
266
  'pdf.zahlung.titel': 'PAYMENT DETAILS',
228
267
  'pdf.zahlung.empfaenger': 'Payee',
229
268
  'pdf.zahlung.iban': 'IBAN',
@@ -273,6 +312,7 @@ const EN = {
273
312
  'einvoice.befreiung.reverseCharge': 'Reverse charge – VAT liability of the recipient',
274
313
  'einvoice.befreiung.kleinunternehmer': 'VAT exempt — small business pursuant to § 6 (1) no. 27 UStG',
275
314
  'einvoice.befreiung.igLieferung': 'VAT-exempt intra-Community supply pursuant to Art. 6 (1) UStG',
315
+ 'einvoice.befreiung.outsideScope': 'Outside the scope of VAT — place of supply abroad (§ 3a (6) UStG)',
276
316
  'einvoice.befreiung.ausfuhr': 'VAT-exempt export delivery pursuant to § 6 (1) no. 1 UStG',
277
317
  'einvoice.zahlbarBis': 'Payable by {datum}',
278
318
  'einheit.piece': 'pcs',
@@ -5,7 +5,7 @@
5
5
  * Betraege sind ueberall ganze Cent. Datumsangaben sind `YYYY-MM-DD` nach
6
6
  * Wiener Kalender.
7
7
  */
8
- import type { CreditNoteReason, CustomerType, DocType, InvoiceLanguage, InvoiceNoticeCode, InvoicePaymentMethod, InvoiceUnit, InvoiceSetupRequirement, InvoiceListStatus, PriceMode, TaxScheme, VatRatePercent } from './vertrag.js';
8
+ import type { CreditNoteReason, CustomerType, DocType, InvoiceLanguage, InvoiceNoticeCode, ItemKind, ReverseChargeReason, InvoicePaymentMethod, InvoiceUnit, InvoiceSetupRequirement, InvoiceListStatus, PriceMode, TaxScheme, VatRatePercent } from './vertrag.js';
9
9
  export interface CustomerInput {
10
10
  type: CustomerType;
11
11
  name: string;
@@ -71,6 +71,8 @@ export interface InvoiceItemInput {
71
71
  quantity: number;
72
72
  /** Einheit aus `INVOICE_UNITS`; ohne Angabe `piece`. */
73
73
  unit?: InvoiceUnit;
74
+ /** Ware oder Leistung; ohne Angabe `goods`. Entscheidet ueber den Steuerfall. */
75
+ kind?: ItemKind;
74
76
  /** Einzelpreis in ganzen Cent, im `priceMode` der Rechnung (netto oder brutto). */
75
77
  unitPriceCents: number;
76
78
  vatRate: VatRatePercent;
@@ -82,7 +84,10 @@ export interface IssueInvoiceRequest {
82
84
  idempotencyKey: string;
83
85
  /** Pflicht ueber 400 € brutto sowie bei Reverse Charge und ig. Lieferung. */
84
86
  customerId?: string;
85
- taxScheme: TaxScheme;
87
+ /** Optional: der Server leitet den Fall ab und prueft eine Angabe dagegen. */
88
+ taxScheme?: TaxScheme;
89
+ /** Pflicht bei `domesticReverseCharge`. */
90
+ reverseChargeReason?: ReverseChargeReason;
86
91
  priceMode: PriceMode;
87
92
  /** Leistungsdatum bzw. Beginn des Leistungszeitraums. */
88
93
  serviceStart: string;
@@ -141,7 +146,7 @@ export interface InvoicePayment {
141
146
  }
142
147
  /**
143
148
  * Ein Hinweis zu einer erfolgreichen Antwort — kein Fehler, sondern etwas,
144
- * das der Aufrufer wissen sollte (heute nur `cash_receipt_required`).
149
+ * das der Aufrufer wissen sollte. Die Codes stehen in `INVOICE_NOTICE_CODES`.
145
150
  */
146
151
  export interface InvoiceNotice {
147
152
  code: InvoiceNoticeCode;
@@ -151,7 +156,11 @@ export interface RecordPaymentResult {
151
156
  invoice: Invoice;
152
157
  payment: InvoicePayment;
153
158
  replayed: boolean;
154
- notice?: InvoiceNotice;
159
+ /**
160
+ * Hinweise zu dieser Zahlung — eine **Liste** wie bei `issueInvoice`
161
+ * (bis 0.21.0 ein einzelnes Objekt). Fehlt, wenn es keinen gibt.
162
+ */
163
+ notice?: InvoiceNotice[];
155
164
  }
156
165
  export interface CancelInvoiceRequest {
157
166
  idempotencyKey: string;
@@ -162,15 +171,23 @@ export interface CancelInvoiceRequest {
162
171
  export interface CreditNoteRequest extends CancelInvoiceRequest {
163
172
  items: InvoiceItemInput[];
164
173
  }
174
+ /**
175
+ * Summen einer Rechnung in Cent, **immer positiv** — auch bei einer Gutschrift
176
+ * (`docType: 'GU'`); das Vorzeichen steht im Belegtyp, nicht im Betrag.
177
+ * Gerechnet wird je Satz wie in [rechnungSummen].
178
+ */
165
179
  export interface InvoiceTotals {
166
180
  netCents: number;
167
181
  vatCents: number;
168
182
  grossCents: number;
169
- byRate: {
170
- rate: number;
171
- netCents: number;
172
- vatCents: number;
173
- }[];
183
+ /** Je USt-Satz, absteigend. `grossCents` ist `netCents + vatCents` (seit 0.22.0 mitgeliefert). */
184
+ byRate: InvoiceRateTotals[];
185
+ }
186
+ export interface InvoiceRateTotals {
187
+ rate: number;
188
+ netCents: number;
189
+ vatCents: number;
190
+ grossCents: number;
174
191
  }
175
192
  export interface EInvoiceStatus {
176
193
  level: string;
@@ -227,6 +244,8 @@ export interface InvoiceItem {
227
244
  subtitle: string;
228
245
  quantity: number;
229
246
  unit: string;
247
+ /** Ware oder Leistung — Altbestand ohne Angabe zaehlt als `goods`. */
248
+ kind: ItemKind;
230
249
  unitPriceCents: number;
231
250
  vatRate: number;
232
251
  discountPct: number;
@@ -235,6 +254,10 @@ export interface InvoiceDetail extends Invoice {
235
254
  items: InvoiceItem[];
236
255
  customer: InvoiceRecipient | null;
237
256
  taxScheme: TaxScheme;
257
+ /** Nur bei `domesticReverseCharge`. */
258
+ reverseChargeReason: ReverseChargeReason | null;
259
+ /** Land, dessen Steuer die Rechnung traegt; Altbestand `AT`. */
260
+ taxCountry: string;
238
261
  priceMode: PriceMode;
239
262
  serviceStart: string | null;
240
263
  serviceEnd: string | null;
@@ -280,6 +303,45 @@ export interface IssueResult {
280
303
  invoice: Invoice;
281
304
  /** `true`, wenn die Anfrage schon einmal ausgefuehrt wurde und die bestehende Rechnung zurueckkommt. */
282
305
  replayed: boolean;
306
+ /**
307
+ * Hinweise zu dieser Rechnung — kein Fehler, sondern etwas, das der Aufrufer
308
+ * wissen sollte. Eine **Liste**, weil mehrere zugleich anfallen koennen: eine
309
+ * bar bezahlte ig. Lieferung traegt sowohl `cash_receipt_required` als auch
310
+ * `recapitulative_statement_due`.
311
+ */
312
+ notice?: InvoiceNotice[];
313
+ }
314
+ /**
315
+ * Was `issueInvoice` mit dieser Anfrage ausstellen wuerde — ohne Nummer, ohne
316
+ * Dokument, ohne Zahlung. Der Probelauf prueft wie das Ausstellen (Einrichtung,
317
+ * Kunde, Steuerfall, Pflichtangaben, Marke, Zahlung) und scheitert mit
318
+ * denselben Fehlercodes.
319
+ */
320
+ export interface InvoicePreview {
321
+ docType: 'RE';
322
+ /** Heutiger Wiener Tag — der Tag, den eine sofort ausgestellte Rechnung truege. */
323
+ invoiceDate: string;
324
+ dueDate: string | null;
325
+ customerId: string | null;
326
+ /** Der abgeleitete Steuerfall. */
327
+ taxScheme: TaxScheme;
328
+ /** Warum dieser Fall gilt (z. B. `customer_country_eu_with_vat_id`). */
329
+ taxSchemeReason: string;
330
+ reverseChargeReason: ReverseChargeReason | null;
331
+ taxCountry: string;
332
+ priceMode: PriceMode;
333
+ totals: InvoiceTotals;
334
+ language: InvoiceLanguage;
335
+ brand: {
336
+ id: string | null;
337
+ name: string | null;
338
+ } | null;
339
+ einvoice: EInvoiceStatus;
340
+ }
341
+ export interface PreviewResult {
342
+ preview: InvoicePreview;
343
+ /** Dieselben Hinweise, die das Ausstellen liefern wuerde. */
344
+ notice?: InvoiceNotice[];
283
345
  }
284
346
  export interface CancelResult {
285
347
  creditNote: Invoice;
@@ -24,13 +24,88 @@ export type RechnungAufruf = (typeof RECHNUNG_AUFRUFE)[number];
24
24
  * Stabile Fehlercodes. Das Fremdsystem verzweigt am Code, der Text darf sich
25
25
  * aendern. `validation` traegt zusaetzlich `errors: [{ field, message }]`.
26
26
  */
27
- export declare const INVOICE_ERROR_CODES: readonly ["validation", "idempotency_conflict", "module_inactive", "customer_not_found", "customer_exists", "short_code_taken", "short_code_immutable", "recipient_required", "invoice_requirements_missing", "invoice_not_found", "invoice_ambiguous", "not_cancellable", "partial_credit_exists", "credit_exceeds_invoice", "einvoice_incomplete", "invoice_api_not_enabled", "invoice_setup_incomplete", "language_not_allowed", "brand_not_found", "not_payable", "payment_exceeds_invoice"];
27
+ export declare const INVOICE_ERROR_CODES: readonly ["validation", "idempotency_conflict", "module_inactive", "customer_not_found", "customer_exists", "short_code_taken", "short_code_immutable", "recipient_required", "invoice_requirements_missing", "invoice_not_found", "invoice_ambiguous", "not_cancellable", "partial_credit_exists", "credit_exceeds_invoice", "einvoice_incomplete", "invoice_api_not_enabled", "invoice_setup_incomplete", "language_not_allowed", "brand_not_found", "not_payable", "payment_exceeds_invoice", "tax_scheme_mismatch", "vat_rate_not_in_country", "reverse_charge_reason_required", "reverse_charge_threshold", "mixed_supply_not_allowed", "oss_not_enabled"];
28
28
  export type InvoiceErrorCode = (typeof INVOICE_ERROR_CODES)[number];
29
29
  /** Gruende einer Gutschrift. Der Server druckt den deutschen Anzeigetext. */
30
30
  export declare const CREDIT_NOTE_REASONS: readonly ["cancellation", "price_reduction", "return", "incorrect_invoice", "other"];
31
31
  export type CreditNoteReason = (typeof CREDIT_NOTE_REASONS)[number];
32
- export declare const TAX_SCHEMES: readonly ["normal", "smallBusiness", "reverseCharge", "igLieferung", "exportThirdCountry"];
32
+ /**
33
+ * Der Steuerfall einer Rechnung. Er wird vom Server **abgeleitet** (Kundenland,
34
+ * Kundenart, UID, Ware oder Leistung); eine mitgeschickte Angabe muss dazu
35
+ * passen, sonst `tax_scheme_mismatch`. Neue Faelle stehen hinten, damit
36
+ * gespeicherte Reihenfolgen gueltig bleiben.
37
+ *
38
+ * - `normal` oesterreichische Umsatzsteuer
39
+ * - `smallBusiness` Kleinunternehmer (§ 6 Abs. 1 Z 27 UStG)
40
+ * - `reverseCharge` Leistung an ein Unternehmen in der EU (Art. 196 MwSt-RL)
41
+ * - `igLieferung` Ware an ein Unternehmen in der EU (Art. 6 Abs. 1 UStG)
42
+ * - `exportThirdCountry` Ware ins Drittland (§ 6 Abs. 1 Z 1 UStG)
43
+ * - `domesticReverseCharge` Uebergang der Steuerschuld im Inland, Grund aus `REVERSE_CHARGE_REASONS`
44
+ * - `oss` B2C in der EU ueber den One-Stop-Shop, Satz des Ziellandes
45
+ * - `outsideScope` Leistung an ein Drittlandsunternehmen — in Oesterreich nicht steuerbar
46
+ */
47
+ export declare const TAX_SCHEMES: readonly ["normal", "smallBusiness", "reverseCharge", "igLieferung", "exportThirdCountry", "domesticReverseCharge", "oss", "outsideScope"];
33
48
  export type TaxScheme = (typeof TAX_SCHEMES)[number];
49
+ /**
50
+ * Gruende fuer den Uebergang der Steuerschuld **im Inland**. Ohne Grund gibt es
51
+ * kein `domesticReverseCharge`: die Bedingungen sind je Fall verschieden, und
52
+ * keine davon laesst sich aus Betrag und Land erraten.
53
+ *
54
+ * `schwelleCents` ist das Entgelt, ab dem der Fall greift — maßgeblich ist das
55
+ * **in der Rechnung ausgewiesene** Entgelt, nicht der Einzelpreis; ein
56
+ * einheitlicher Liefervorgang darf dafuer nicht auf mehrere Rechnungen
57
+ * aufgeteilt werden (UStR Rz 2605d).
58
+ */
59
+ export declare const REVERSE_CHARGE_REASONS: Readonly<{
60
+ construction: {
61
+ stelle: string;
62
+ schwelleCents: null;
63
+ };
64
+ scrap: {
65
+ stelle: string;
66
+ schwelleCents: null;
67
+ };
68
+ mobile_devices: {
69
+ stelle: string;
70
+ schwelleCents: number;
71
+ };
72
+ it_devices: {
73
+ stelle: string;
74
+ schwelleCents: number;
75
+ };
76
+ metals: {
77
+ stelle: string;
78
+ schwelleCents: null;
79
+ };
80
+ emission_certificates: {
81
+ stelle: string;
82
+ schwelleCents: null;
83
+ };
84
+ gas_electricity: {
85
+ stelle: string;
86
+ schwelleCents: null;
87
+ };
88
+ energy_certificates: {
89
+ stelle: string;
90
+ schwelleCents: null;
91
+ };
92
+ investment_gold: {
93
+ stelle: string;
94
+ schwelleCents: null;
95
+ };
96
+ security_transfer: {
97
+ stelle: string;
98
+ schwelleCents: null;
99
+ };
100
+ foreign_supplier: {
101
+ stelle: string;
102
+ schwelleCents: null;
103
+ };
104
+ }>;
105
+ export type ReverseChargeReason = keyof typeof REVERSE_CHARGE_REASONS;
106
+ /** Ware oder Leistung — ohne das laesst sich ig. Lieferung nicht von Reverse Charge trennen. */
107
+ export declare const ITEM_KINDS: readonly ["goods", "service"];
108
+ export type ItemKind = (typeof ITEM_KINDS)[number];
34
109
  export declare const PRICE_MODES: readonly ["net", "gross"];
35
110
  export type PriceMode = (typeof PRICE_MODES)[number];
36
111
  export declare const VAT_RATES: readonly [0, 10, 13, 20];
@@ -66,7 +141,7 @@ export type InvoicePaymentMethod = (typeof INVOICE_PAYMENT_METHODS)[number];
66
141
  * Hinweise, die eine erfolgreiche Antwort zusaetzlich tragen kann (`data.notice`).
67
142
  * Sie sind keine Fehler: der Aufruf hat gewirkt, es gibt nur etwas zu wissen.
68
143
  */
69
- export declare const INVOICE_NOTICE_CODES: readonly ["cash_receipt_required"];
144
+ export declare const INVOICE_NOTICE_CODES: readonly ["cash_receipt_required", "recapitulative_statement_due", "place_of_supply_check"];
70
145
  export type InvoiceNoticeCode = (typeof INVOICE_NOTICE_CODES)[number];
71
146
  /**
72
147
  * Einheiten einer Position. Die API nimmt nur diese Schluessel an; gedruckt
@@ -19,7 +19,7 @@
19
19
  * Nummer, Summen — ist bewusst **nicht** setzbar.
20
20
  */
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.RECHNUNG_MINDESTENS_EINS = exports.RECHNUNG_GENAU_EINS = exports.RECHNUNG_ANFRAGEN = exports.PAYMENT_FELDER = exports.POSITION_FELDER = exports.KUNDE_FELDER = exports.INVOICE_SETUP_REQUIREMENTS = exports.RECHNUNG_EINHEITEN_CODES = exports.INVOICE_UNITS = exports.INVOICE_NOTICE_CODES = exports.INVOICE_PAYMENT_METHODS = exports.INVOICE_LANGUAGES = exports.EINVOICE_FORMATS = exports.DOC_TYPES = exports.INVOICE_LIST_STATUS = exports.CUSTOMER_TYPES = exports.VAT_RATES = exports.PRICE_MODES = exports.TAX_SCHEMES = exports.CREDIT_NOTE_REASONS = exports.INVOICE_ERROR_CODES = exports.RECHNUNG_AUFRUFE = exports.RECHNUNG_VERTRAG_VERSION = void 0;
22
+ exports.RECHNUNG_MINDESTENS_EINS = exports.RECHNUNG_GENAU_EINS = exports.RECHNUNG_ANFRAGEN = exports.PAYMENT_FELDER = exports.POSITION_FELDER = exports.KUNDE_FELDER = exports.INVOICE_SETUP_REQUIREMENTS = exports.RECHNUNG_EINHEITEN_CODES = exports.INVOICE_UNITS = exports.INVOICE_NOTICE_CODES = exports.INVOICE_PAYMENT_METHODS = exports.INVOICE_LANGUAGES = exports.EINVOICE_FORMATS = exports.DOC_TYPES = exports.INVOICE_LIST_STATUS = exports.CUSTOMER_TYPES = exports.VAT_RATES = exports.PRICE_MODES = exports.ITEM_KINDS = exports.REVERSE_CHARGE_REASONS = exports.TAX_SCHEMES = exports.CREDIT_NOTE_REASONS = exports.INVOICE_ERROR_CODES = exports.RECHNUNG_AUFRUFE = exports.RECHNUNG_VERTRAG_VERSION = void 0;
23
23
  exports.RECHNUNG_VERTRAG_VERSION = 1;
24
24
  exports.RECHNUNG_AUFRUFE = [
25
25
  'createCustomer',
@@ -63,6 +63,12 @@ exports.INVOICE_ERROR_CODES = [
63
63
  'brand_not_found',
64
64
  'not_payable',
65
65
  'payment_exceeds_invoice',
66
+ 'tax_scheme_mismatch',
67
+ 'vat_rate_not_in_country',
68
+ 'reverse_charge_reason_required',
69
+ 'reverse_charge_threshold',
70
+ 'mixed_supply_not_allowed',
71
+ 'oss_not_enabled',
66
72
  ];
67
73
  /** Gruende einer Gutschrift. Der Server druckt den deutschen Anzeigetext. */
68
74
  exports.CREDIT_NOTE_REASONS = [
@@ -72,7 +78,56 @@ exports.CREDIT_NOTE_REASONS = [
72
78
  'incorrect_invoice',
73
79
  'other',
74
80
  ];
75
- exports.TAX_SCHEMES = ['normal', 'smallBusiness', 'reverseCharge', 'igLieferung', 'exportThirdCountry'];
81
+ /**
82
+ * Der Steuerfall einer Rechnung. Er wird vom Server **abgeleitet** (Kundenland,
83
+ * Kundenart, UID, Ware oder Leistung); eine mitgeschickte Angabe muss dazu
84
+ * passen, sonst `tax_scheme_mismatch`. Neue Faelle stehen hinten, damit
85
+ * gespeicherte Reihenfolgen gueltig bleiben.
86
+ *
87
+ * - `normal` oesterreichische Umsatzsteuer
88
+ * - `smallBusiness` Kleinunternehmer (§ 6 Abs. 1 Z 27 UStG)
89
+ * - `reverseCharge` Leistung an ein Unternehmen in der EU (Art. 196 MwSt-RL)
90
+ * - `igLieferung` Ware an ein Unternehmen in der EU (Art. 6 Abs. 1 UStG)
91
+ * - `exportThirdCountry` Ware ins Drittland (§ 6 Abs. 1 Z 1 UStG)
92
+ * - `domesticReverseCharge` Uebergang der Steuerschuld im Inland, Grund aus `REVERSE_CHARGE_REASONS`
93
+ * - `oss` B2C in der EU ueber den One-Stop-Shop, Satz des Ziellandes
94
+ * - `outsideScope` Leistung an ein Drittlandsunternehmen — in Oesterreich nicht steuerbar
95
+ */
96
+ exports.TAX_SCHEMES = [
97
+ 'normal',
98
+ 'smallBusiness',
99
+ 'reverseCharge',
100
+ 'igLieferung',
101
+ 'exportThirdCountry',
102
+ 'domesticReverseCharge',
103
+ 'oss',
104
+ 'outsideScope',
105
+ ];
106
+ /**
107
+ * Gruende fuer den Uebergang der Steuerschuld **im Inland**. Ohne Grund gibt es
108
+ * kein `domesticReverseCharge`: die Bedingungen sind je Fall verschieden, und
109
+ * keine davon laesst sich aus Betrag und Land erraten.
110
+ *
111
+ * `schwelleCents` ist das Entgelt, ab dem der Fall greift — maßgeblich ist das
112
+ * **in der Rechnung ausgewiesene** Entgelt, nicht der Einzelpreis; ein
113
+ * einheitlicher Liefervorgang darf dafuer nicht auf mehrere Rechnungen
114
+ * aufgeteilt werden (UStR Rz 2605d).
115
+ */
116
+ exports.REVERSE_CHARGE_REASONS = Object.freeze({
117
+ construction: { stelle: '§ 19 Abs. 1a UStG', schwelleCents: null },
118
+ scrap: { stelle: 'Schrott-UStV, BGBl. II Nr. 129/2007', schwelleCents: null },
119
+ mobile_devices: { stelle: '§ 19 Abs. 1e lit. b UStG', schwelleCents: 500_000 },
120
+ it_devices: { stelle: '§ 2 Z 1 UStBBKV, BGBl. II Nr. 369/2013', schwelleCents: 500_000 },
121
+ metals: { stelle: '§ 2 Z 4 UStBBKV', schwelleCents: null },
122
+ emission_certificates: { stelle: '§ 19 Abs. 1e lit. a UStG', schwelleCents: null },
123
+ gas_electricity: { stelle: '§ 2 Z 2 UStBBKV', schwelleCents: null },
124
+ energy_certificates: { stelle: '§ 2 Z 3 UStBBKV', schwelleCents: null },
125
+ investment_gold: { stelle: '§ 2 Z 5 UStBBKV', schwelleCents: null },
126
+ security_transfer: { stelle: '§ 19 Abs. 1b UStG', schwelleCents: null },
127
+ foreign_supplier: { stelle: '§ 19 Abs. 1 zweiter Satz UStG', schwelleCents: null },
128
+ });
129
+ /** Ware oder Leistung — ohne das laesst sich ig. Lieferung nicht von Reverse Charge trennen. */
130
+ exports.ITEM_KINDS = ['goods', 'service'];
76
131
  exports.PRICE_MODES = ['net', 'gross'];
77
132
  exports.VAT_RATES = [0, 10, 13, 20];
78
133
  exports.CUSTOMER_TYPES = ['private', 'company'];
@@ -100,7 +155,15 @@ exports.INVOICE_PAYMENT_METHODS = ['transfer', 'card', 'online', 'cash'];
100
155
  * Hinweise, die eine erfolgreiche Antwort zusaetzlich tragen kann (`data.notice`).
101
156
  * Sie sind keine Fehler: der Aufruf hat gewirkt, es gibt nur etwas zu wissen.
102
157
  */
103
- exports.INVOICE_NOTICE_CODES = ['cash_receipt_required'];
158
+ exports.INVOICE_NOTICE_CODES = [
159
+ 'cash_receipt_required',
160
+ /** Ig. Lieferung und grenzueberschreitendes Reverse Charge: die Zusammenfassende
161
+ * Meldung ist materielle Voraussetzung (Art. 7 Abs. 1 Z 5 UStG). */
162
+ 'recapitulative_statement_due',
163
+ /** Leistung an eine Privatperson im Drittland: der Leistungsort haengt von der
164
+ * Art der Leistung ab — wir nehmen den oesterreichischen Fall an. */
165
+ 'place_of_supply_check',
166
+ ];
104
167
  /**
105
168
  * Einheiten einer Position. Die API nimmt nur diese Schluessel an; gedruckt
106
169
  * wird das Kuerzel in der Sprache der Rechnung (`RECHNUNG_TEXTE`,
@@ -277,6 +340,8 @@ exports.POSITION_FELDER = Object.freeze({
277
340
  quantity: { typ: 'number', pflicht: true, min: 0, exklusivMin: true, max: 1_000_000, nachkomma: 3 },
278
341
  /** Einheit aus `INVOICE_UNITS`; ohne Angabe `piece`. */
279
342
  unit: { typ: 'enum', pflicht: false, werte: exports.INVOICE_UNITS },
343
+ /** Ware oder Leistung; ohne Angabe `goods`. Entscheidet ueber den Steuerfall. */
344
+ kind: { typ: 'enum', pflicht: false, werte: exports.ITEM_KINDS },
280
345
  unitPriceCents: { typ: 'integer', pflicht: true, min: 0, max: 100_000_000 },
281
346
  vatRate: { typ: 'enum', pflicht: true, werte: exports.VAT_RATES },
282
347
  discountPct: { typ: 'number', pflicht: false, min: 0, max: 100, nachkomma: 2 },
@@ -325,7 +390,14 @@ exports.RECHNUNG_ANFRAGEN = Object.freeze({
325
390
  issueInvoice: {
326
391
  idempotencyKey: idempotencyKey(true),
327
392
  customerId: id,
328
- taxScheme: { typ: 'enum', pflicht: true, werte: exports.TAX_SCHEMES },
393
+ /**
394
+ * Optional: der Server leitet den Fall ab. Eine Angabe wird geprueft und
395
+ * muss passen (`tax_scheme_mismatch`) — so faellt eine falsche Zuordnung
396
+ * im Fremdsystem auf, statt eine falsche Rechnung zu erzeugen.
397
+ */
398
+ taxScheme: { typ: 'enum', pflicht: false, werte: exports.TAX_SCHEMES },
399
+ /** Pflicht bei `domesticReverseCharge`, sonst nicht erlaubt. */
400
+ reverseChargeReason: { typ: 'enum', pflicht: false, werte: Object.keys(exports.REVERSE_CHARGE_REASONS) },
329
401
  priceMode: { typ: 'enum', pflicht: true, werte: exports.PRICE_MODES },
330
402
  serviceStart: datum(true),
331
403
  serviceEnd: datum(),
@@ -348,6 +420,12 @@ exports.RECHNUNG_ANFRAGEN = Object.freeze({
348
420
  * und ein sofort geholtes PDF Zahlungsinformationen traegt.
349
421
  */
350
422
  payment: { typ: 'object', pflicht: false, felder: exports.PAYMENT_FELDER },
423
+ /**
424
+ * Probelauf: alles pruefen und rechnen wie beim Ausstellen, aber nichts
425
+ * festschreiben — keine Nummer, kein Dokument, keine Zahlung, kein
426
+ * Idempotenz-Eintrag. Die Antwort traegt `preview` statt `invoice`.
427
+ */
428
+ dryRun: { typ: 'boolean', pflicht: false },
351
429
  },
352
430
  cancelInvoice: {
353
431
  idempotencyKey: idempotencyKey(true),
@@ -87,7 +87,6 @@ export declare function causeDigest(ursache: unknown, geheimnisse: readonly stri
87
87
  * demselben Grund **keinen** Vorgabewert.
88
88
  */
89
89
  export declare function fehlerDetails(daten: unknown, geheimnisse: readonly string[]): Record<string, unknown>;
90
- /** Fachlicher Fehler: HTTP 200, aber `status: 'error'` im Rumpf. */
91
90
  export declare class KasseneckApiError extends Error {
92
91
  readonly name = "KasseneckApiError";
93
92
  /** Aufgerufene Backend-Funktion, z. B. `createReceipt`. */
@@ -164,6 +164,29 @@ function sieben(wert, geheimnisse, tiefe) {
164
164
  return raus;
165
165
  }
166
166
  /** Fachlicher Fehler: HTTP 200, aber `status: 'error'` im Rumpf. */
167
+ /**
168
+ * Die Feldfehler einer Pruefantwort (`errors: [{ field, message }]`) als
169
+ * Anhang der Fehlermeldung — sonst stuende im Log nur „Bitte Eingaben
170
+ * pruefen." und niemand wuesste, welches Feld gemeint ist. Hoechstens fuenf;
171
+ * vollstaendig bleiben sie in `details.errors`.
172
+ */
173
+ function feldHinweis(details) {
174
+ const roh = details['errors'];
175
+ if (!Array.isArray(roh))
176
+ return '';
177
+ const teile = [];
178
+ for (const e of roh) {
179
+ if (e === null || typeof e !== 'object')
180
+ continue;
181
+ const { field, message } = e;
182
+ if (typeof field === 'string' && typeof message === 'string')
183
+ teile.push(`${field}: ${message}`);
184
+ }
185
+ if (!teile.length)
186
+ return '';
187
+ const mehr = teile.length > 5 ? ` (+${teile.length - 5} weitere)` : '';
188
+ return ` [${teile.slice(0, 5).join('; ')}${mehr}]`;
189
+ }
167
190
  export class KasseneckApiError extends Error {
168
191
  name = 'KasseneckApiError';
169
192
  /** Aufgerufene Backend-Funktion, z. B. `createReceipt`. */
@@ -187,7 +210,7 @@ export class KasseneckApiError extends Error {
187
210
  */
188
211
  details;
189
212
  constructor(functionName, serverMessage, details = {}, code) {
190
- super(`${functionName} fehlgeschlagen: ${serverMessage}`);
213
+ super(`${functionName} fehlgeschlagen: ${serverMessage}${feldHinweis(details)}`);
191
214
  this.functionName = functionName;
192
215
  this.serverMessage = serverMessage;
193
216
  this.details = details;
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import { type FetchLike } from '../client/transport.js';
8
8
  import type { EInvoiceFormat, InvoiceLanguage } from './vertrag.js';
9
- import type { Brand, CancelInvoiceRequest, CancelResult, CreditNoteRequest, CreditNoteResult, Customer, CustomerInput, CustomerPage, CustomerSearch, InvoiceDetail, InvoiceListQuery, InvoicePage, InvoiceSetupStatus, IssueInvoiceRequest, IssueResult, RecordPaymentRequest, RecordPaymentResult } from './typen.js';
9
+ import type { Brand, CancelInvoiceRequest, CancelResult, CreditNoteRequest, CreditNoteResult, Customer, CustomerInput, CustomerPage, CustomerSearch, InvoiceDetail, InvoiceListQuery, InvoicePage, InvoiceSetupStatus, IssueInvoiceRequest, IssueResult, PreviewResult, RecordPaymentRequest, RecordPaymentResult } from './typen.js';
10
10
  export interface RechnungApiOptions {
11
11
  /** `api_key` des Kontos (`kr_live_…` / `kr_test_…`). Gehoert auf einen Server. */
12
12
  apiKey: string;
@@ -29,6 +29,8 @@ export interface RechnungApi {
29
29
  updateCustomer(customerId: string, patch: Partial<CustomerInput>): Promise<Customer>;
30
30
  searchCustomers(suche: CustomerSearch): Promise<CustomerPage>;
31
31
  issueInvoice(anfrage: IssueInvoiceRequest): Promise<IssueResult>;
32
+ /** Probelauf: pruefen und rechnen wie `issueInvoice`, ohne auszustellen. */
33
+ previewInvoice(anfrage: IssueInvoiceRequest): Promise<PreviewResult>;
32
34
  cancelInvoice(anfrage: CancelInvoiceRequest): Promise<CancelResult>;
33
35
  createCreditNote(anfrage: CreditNoteRequest): Promise<CreditNoteResult>;
34
36
  getInvoice(kennung: {
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import { createBinaryTransport, createTransport } from '../client/transport.js';
8
8
  import { rechnungKeyAuth } from './auth.js';
9
- import { cancelInvoice, createCreditNote, createCustomer, getCustomer, getInvoice, getInvoicePdf, getInvoiceSetupStatus, getInvoiceXml, issueInvoice, listBrands, listInvoices, recordInvoicePayment, searchCustomers, updateCustomer, } from './endpunkte.js';
9
+ import { cancelInvoice, createCreditNote, createCustomer, getCustomer, getInvoice, getInvoicePdf, getInvoiceSetupStatus, getInvoiceXml, issueInvoice, listBrands, previewInvoice, listInvoices, recordInvoicePayment, searchCustomers, updateCustomer, } from './endpunkte.js';
10
10
  export function createRechnungApi(optionen) {
11
11
  const transportOptionen = {
12
12
  auth: rechnungKeyAuth({ apiKey: optionen.apiKey }),
@@ -22,6 +22,7 @@ export function createRechnungApi(optionen) {
22
22
  updateCustomer: (id, patch) => updateCustomer(rufen, id, patch),
23
23
  searchCustomers: (suche) => searchCustomers(rufen, suche),
24
24
  issueInvoice: (anfrage) => issueInvoice(rufen, anfrage),
25
+ previewInvoice: (anfrage) => previewInvoice(rufen, anfrage),
25
26
  cancelInvoice: (anfrage) => cancelInvoice(rufen, anfrage),
26
27
  createCreditNote: (anfrage) => createCreditNote(rufen, anfrage),
27
28
  getInvoice: (kennung) => getInvoice(rufen, kennung),
@@ -18,7 +18,7 @@
18
18
  */
19
19
  import type { InternerBinaerTransport, InternerTransport } from '../client/aufrufe.js';
20
20
  import type { EInvoiceFormat, InvoiceLanguage } from './vertrag.js';
21
- import type { Brand, CancelInvoiceRequest, CancelResult, CreditNoteRequest, CreditNoteResult, Customer, CustomerInput, CustomerPage, CustomerSearch, InvoiceDetail, InvoiceListQuery, InvoicePage, InvoiceSetupStatus, IssueInvoiceRequest, IssueResult, RecordPaymentRequest, RecordPaymentResult } from './typen.js';
21
+ import type { Brand, CancelInvoiceRequest, CancelResult, CreditNoteRequest, CreditNoteResult, Customer, CustomerInput, CustomerPage, CustomerSearch, InvoiceDetail, InvoiceListQuery, InvoicePage, InvoiceSetupStatus, IssueInvoiceRequest, IssueResult, PreviewResult, RecordPaymentRequest, RecordPaymentResult } from './typen.js';
22
22
  export declare function createCustomer(rufen: InternerTransport, customer: CustomerInput, optionen?: {
23
23
  idempotencyKey?: string;
24
24
  }): Promise<Customer>;
@@ -30,6 +30,17 @@ export declare function getCustomer(rufen: InternerTransport, kennung: {
30
30
  export declare function updateCustomer(rufen: InternerTransport, customerId: string, patch: Partial<CustomerInput>): Promise<Customer>;
31
31
  export declare function searchCustomers(rufen: InternerTransport, suche: CustomerSearch): Promise<CustomerPage>;
32
32
  export declare function issueInvoice(rufen: InternerTransport, anfrage: IssueInvoiceRequest): Promise<IssueResult>;
33
+ /**
34
+ * Probelauf von `issueInvoice`: dieselbe Anfrage wird geprueft und gerechnet
35
+ * wie beim Ausstellen, aber nichts festgeschrieben. Die Antwort nennt Summen,
36
+ * Steuerfall, Sprache, Marke und die Hinweise — oder scheitert mit demselben
37
+ * Fehlercode, mit dem das Ausstellen scheitern wuerde.
38
+ *
39
+ * Der `idempotencyKey` wird nicht verbraucht: dieselbe Anfrage laesst sich
40
+ * danach unveraendert ausstellen. Verbindlich ist das Ausstellen — zwischen
41
+ * Probelauf und Ausstellen kann sich der Kunde oder das Konto aendern.
42
+ */
43
+ export declare function previewInvoice(rufen: InternerTransport, anfrage: IssueInvoiceRequest): Promise<PreviewResult>;
33
44
  export declare function cancelInvoice(rufen: InternerTransport, anfrage: CancelInvoiceRequest): Promise<CancelResult>;
34
45
  export declare function createCreditNote(rufen: InternerTransport, anfrage: CreditNoteRequest): Promise<CreditNoteResult>;
35
46
  export declare function getInvoice(rufen: InternerTransport, kennung: {