@kreiseck/kasseneck-api 0.22.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/README.md +32 -0
- package/dist/cjs/printing/escpos.d.ts +0 -4
- package/dist/cjs/printing/escpos.js +26 -32
- package/dist/cjs/rechnung/index.d.ts +1 -0
- package/dist/cjs/rechnung/index.js +12 -1
- package/dist/cjs/rechnung/rechnen.d.ts +123 -0
- package/dist/cjs/rechnung/rechnen.js +327 -0
- package/dist/cjs/rechnung/summen.d.ts +3 -2
- package/dist/cjs/rechnung/summen.js +3 -10
- package/dist/cjs/rechnung/vertrag.d.ts +1 -1
- package/dist/cjs/rechnung/vertrag.js +2 -0
- package/dist/esm/printing/escpos.d.ts +0 -4
- package/dist/esm/printing/escpos.js +26 -32
- package/dist/esm/rechnung/index.d.ts +1 -0
- package/dist/esm/rechnung/index.js +1 -0
- package/dist/esm/rechnung/rechnen.d.ts +123 -0
- package/dist/esm/rechnung/rechnen.js +316 -0
- package/dist/esm/rechnung/summen.d.ts +3 -2
- package/dist/esm/rechnung/summen.js +3 -9
- package/dist/esm/rechnung/vertrag.d.ts +1 -1
- package/dist/esm/rechnung/vertrag.js +2 -0
- package/fixtures/hobex-hps-codes.json +1 -1
- package/fixtures/kasse-texte.json +1 -1
- package/fixtures/oberflaeche.json +4 -2
- package/fixtures/position-aus-euro.json +107 -0
- package/fixtures/rechnung-api.schema.json +4 -2
- package/fixtures/rechnung-rechnen-zufall.json +8451 -0
- package/fixtures/rechnung-rechnen.json +304 -0
- package/fixtures/rechnung-texte.json +1 -1
- package/package.json +13 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,56 @@ Was vor 0.7.0 geschah, steht in der Commit-Historie (`git log`); ab hier wird
|
|
|
4
4
|
es hier geführt. Ein Eintrag nennt die Änderung **und ihren Grund** —
|
|
5
5
|
nur der Grund überlebt den nächsten Umbau.
|
|
6
6
|
|
|
7
|
+
## 0.25.0
|
|
8
|
+
|
|
9
|
+
- ESC/POS: den Sofort-Reset der Ausrichtung direkt nach QR-Code, QR-Rasterbild und
|
|
10
|
+
Logo-Rasterbild entfernt. Er behandelte nur ein Symptom: seit 0.24.0 steht `ESC a`
|
|
11
|
+
ohnehin vor `ESC $`, und eine volle Zeile bekommt gar keinen Positionsbefehl mehr —
|
|
12
|
+
der Ausrichtungsbefehl des naechsten Elements steht damit selbst immer am
|
|
13
|
+
Zeilenanfang und gilt. Der erzeugte Bytestrom ist dadurch wieder deckungsgleich mit
|
|
14
|
+
dem Dart-Zwilling; bisher war dieser Reset der einzige Unterschied zwischen beiden.
|
|
15
|
+
|
|
16
|
+
## 0.24.0
|
|
17
|
+
|
|
18
|
+
- ESC/POS: `ESC a` steht vor `ESC $`, eine volle Zeile bekommt keinen Positionsbefehl mehr.
|
|
19
|
+
Der Drucker nimmt die Ausrichtung nur am Zeilenanfang an; bisher blieb nach dem QR-Code die
|
|
20
|
+
Zentrierung stehen und zentrierte jede Zeile darunter ein zweites Mal.
|
|
21
|
+
|
|
22
|
+
## 0.23.0
|
|
23
|
+
|
|
24
|
+
### Rechnung: der Rechenkern in ganzen Zahlen
|
|
25
|
+
|
|
26
|
+
**Anlass:** Vier Umsetzungen (Server, dieses Paket, Dart, Panel) mussten dieselbe
|
|
27
|
+
Reihenfolge von Gleitkomma-Schritten nachbauen, damit Grenzfälle gleich runden.
|
|
28
|
+
Ein Cent Unterschied im Brutto-Modus hat das am 16.09.2026 sichtbar gemacht.
|
|
29
|
+
|
|
30
|
+
- **Neu: Unterpfad `@kreiseck/kasseneck-api/rechnung/rechnen`** — rein, ohne
|
|
31
|
+
Transport, auch für den Browser. Darin:
|
|
32
|
+
- `rechnungRechnen(positionen, { priceMode, taxScheme })` rechnet exakt in
|
|
33
|
+
ganzen Zahlen (BigInt) und rundet einmal je USt-Satz. Preise in Millionstel
|
|
34
|
+
Euro, Mengen in Tausendstel, Rabatt und Satz in Hundertstel-Prozent.
|
|
35
|
+
- `positionAusEuro(item)` wandelt eine Euro-Position verlustfrei um oder
|
|
36
|
+
nennt Feld und Grund.
|
|
37
|
+
- `anteiligerPreis`, `satzSchluessel`, `satzText`, `preisText`.
|
|
38
|
+
- `RechenFehler` mit `code` (`amount_too_large`, `kein_ganzzahlwert`,
|
|
39
|
+
`ausserhalb`), Feld und Index.
|
|
40
|
+
- **Prüffälle im Paket:** `fixtures/rechnung-rechnen.json` (20 Fälle von
|
|
41
|
+
Hand), `fixtures/rechnung-rechnen-zufall.json` (400 aus einer unabhängigen
|
|
42
|
+
Referenz in Python) und `fixtures/position-aus-euro.json`. Server,
|
|
43
|
+
Dart-Zwilling und Panel werden gegen dieselben Dateien prüfen.
|
|
44
|
+
- **Fehlerkatalog um zwei Codes erweitert:** `einvoice_unavailable` (zu dieser
|
|
45
|
+
Rechnung entsteht keine E-Rechnung, Grund im `reason`) und
|
|
46
|
+
`amount_too_large` (Betrag über der Grenze des Ganzzahlkerns) — beide hinten
|
|
47
|
+
angehängt, damit gespeicherte Reihenfolgen gültig bleiben. Der Katalog geht
|
|
48
|
+
dem Server bewusst voraus, damit Fremdsysteme beide Codes behandeln können,
|
|
49
|
+
bevor der Server sie sendet; heute sendet der Server keinen von beiden,
|
|
50
|
+
`amount_too_large` erst ab dessen Umstieg auf den Ganzzahlkern.
|
|
51
|
+
- **Unverändert:** `rechnungSummen`, `fixtures/rechnung-summen.json` und Form
|
|
52
|
+
von Anfrage und Antwort der Rechnungs-API — der Fehlerkatalog wächst nur
|
|
53
|
+
additiv (s. o.). Der Kern rundet an Halbcent-Grenzen richtig, `rechnungSummen`
|
|
54
|
+
rechnet weiterhin wie der Server heute; beides wird in 0.24.0
|
|
55
|
+
zusammengeführt. Wer schon vorab genau rechnen will, nimmt `previewInvoice`.
|
|
56
|
+
|
|
7
57
|
## 0.22.0
|
|
8
58
|
|
|
9
59
|
### Rechnung: Brutto bleibt Brutto, Hinweise kommen an, Probelauf
|
package/README.md
CHANGED
|
@@ -577,6 +577,37 @@ aufwärts), je Satz, dann summiert. Die Prüffälle liegen in
|
|
|
577
577
|
`fixtures/rechnung-summen.json`. Die Summen sind auch bei Gutschriften positiv —
|
|
578
578
|
das Vorzeichen steht im Belegtyp (`docType: 'GU'`).
|
|
579
579
|
|
|
580
|
+
**Vorab rechnen, ohne Server.** `@kreiseck/kasseneck-api/rechnung/rechnen` ist
|
|
581
|
+
der reine Rechenkern dahinter: kein Transport, kein Zugangsschlüssel, läuft
|
|
582
|
+
auch im Browser (Panel). Er rechnet intern mit ganzen Zahlen (BigInt) statt
|
|
583
|
+
Gleitkomma und rundet genau einmal je USt-Satz — Preise in Millionstel Euro
|
|
584
|
+
(`unitPriceMicros`), Mengen in Tausendstel (`quantityMilli`), Rabatt und Satz
|
|
585
|
+
in Hundertstel-Prozent (`discountBp`, `vatRateBp`):
|
|
586
|
+
|
|
587
|
+
```ts
|
|
588
|
+
import { rechnungRechnen } from '@kreiseck/kasseneck-api/rechnung/rechnen';
|
|
589
|
+
|
|
590
|
+
rechnungRechnen(
|
|
591
|
+
[{ unitPriceMicros: 14_790_000, quantityMilli: 1000, vatRateBp: 2000 }],
|
|
592
|
+
{ priceMode: 'gross' },
|
|
593
|
+
);
|
|
594
|
+
// { netCents: 1233, vatCents: 246, grossCents: 1479, byRate: [{ rateBp: 2000, … }], lines: […] }
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
`positionAusEuro(item)` wandelt eine Euro-Position (`unitPrice`, `quantity`,
|
|
598
|
+
`vatRate`, `discountPct`) verlustfrei in diese Form um oder nennt Feld und
|
|
599
|
+
Grund, wenn das nicht geht. Die Prüffälle liegen in
|
|
600
|
+
`fixtures/rechnung-rechnen.json`, `fixtures/rechnung-rechnen-zufall.json` und
|
|
601
|
+
`fixtures/position-aus-euro.json`. **Noch nicht zusammengeführt** mit
|
|
602
|
+
`rechnungSummen`: bis 0.24.0 rechnen beide parallel und weichen an
|
|
603
|
+
Halbcent-Grenzen bewusst voneinander ab — **je USt-Satz** bis zu 1 Cent bei
|
|
604
|
+
einmal gerundeten Werten (Netto und USt im Netto-Modus, Brutto im
|
|
605
|
+
Brutto-Modus) und bis zu 2 Cent bei abgeleiteten (Summe zweier Rundungen). Bei
|
|
606
|
+
mehreren Sätzen summiert sich das: eine Rechnung über drei Sätze kann deshalb
|
|
607
|
+
3 Cent auseinanderliegen. Der Kern rundet dort richtig, `rechnungSummen`
|
|
608
|
+
rechnet weiterhin wie der Server heute. Verbindlich
|
|
609
|
+
für den ausgewiesenen Betrag bleibt bis dahin `previewInvoice`.
|
|
610
|
+
|
|
580
611
|
**Hinweise** (`notice`) sind immer eine Liste — bei `issueInvoice`,
|
|
581
612
|
`previewInvoice` und `recordInvoicePayment`. Eine ig. Lieferung trägt
|
|
582
613
|
`recapitulative_statement_due` (Zusammenfassende Meldung), eine bar bezahlte
|
|
@@ -621,6 +652,7 @@ gegen genau diese Datei.
|
|
|
621
652
|
| `…/kasse` | Kachel-Kasse: Kassen-Einstellungen (betriebsweit / je Gerät), Artikelgruppen und Artikel für Kacheln, Rabattverteilung je Steuersatz, Reichweiten der Kassen-Rechte |
|
|
622
653
|
| `…/partner` | Partner-API: Betriebe anlegen, FinanzOnline-Link, Signatur, Kassen, Zugangsdaten, Webhooks samt Signaturprüfung. **Gehört auf einen Server.** |
|
|
623
654
|
| `…/rechnung` | Rechnungs-API: Kunden anlegen und suchen, Rechnungen festgeschrieben ausstellen, Gutschrift und Storno, PDF und E-Rechnung-XML; der Vertrag als Daten. **Gehört auf einen Server.** |
|
|
655
|
+
| `…/rechnung/rechnen` | Reiner Rechenkern für Rechnungssummen (Ganzzahlen, kein Transport, keine Abhängigkeit außer Typen) — darf auch im Browser laufen. |
|
|
624
656
|
| `…/react` | Dünner React-Adapter, der ein Beleg-Layout zeichnet. Braucht React. |
|
|
625
657
|
| `…/fixtures/*` | Golden-Belege (JSON): Eingaben `belege/<name>.json`, zugesagte Zeilenausgabe `erwartet/<name>.lines.json`, `manifest.json` mit Prüfsummen — dieselben Dateien prüfen Backend, Browser-Kasse und Flutter-Paket. |
|
|
626
658
|
|
|
@@ -208,10 +208,6 @@ export declare function escPosSetGlobalFont(doc: EscPosDocument, font: PosFont |
|
|
|
208
208
|
* weglaesst, schaltet fett also ab.
|
|
209
209
|
*/
|
|
210
210
|
export declare function escPosSetStyles(doc: EscPosDocument, styles?: PosStyles): void;
|
|
211
|
-
/**
|
|
212
|
-
* Interner Textdruck: absolute Position setzen (`ESC $`), Stil senden, Bytes
|
|
213
|
-
* ausgeben. [colInd]/[colWidth] beschreiben die Spalte im Zwoelftel-Raster.
|
|
214
|
-
*/
|
|
215
211
|
/**
|
|
216
212
|
* Wortweiser Umbruch von (kodierten) Text-Bytes auf hoechstens `max` Zeichen
|
|
217
213
|
* je Zeile: geschnitten wird am letzten Leerzeichen innerhalb der Grenze
|
|
@@ -344,10 +344,6 @@ function escPosSetStyles(doc, styles = {}) {
|
|
|
344
344
|
alt.codeTable = codepage;
|
|
345
345
|
}
|
|
346
346
|
}
|
|
347
|
-
/**
|
|
348
|
-
* Interner Textdruck: absolute Position setzen (`ESC $`), Stil senden, Bytes
|
|
349
|
-
* ausgeben. [colInd]/[colWidth] beschreiben die Spalte im Zwoelftel-Raster.
|
|
350
|
-
*/
|
|
351
347
|
/**
|
|
352
348
|
* Wortweiser Umbruch von (kodierten) Text-Bytes auf hoechstens `max` Zeichen
|
|
353
349
|
* je Zeile: geschnitten wird am letzten Leerzeichen innerhalb der Grenze
|
|
@@ -449,27 +445,38 @@ function wortzeilenText(text, max) {
|
|
|
449
445
|
out.push(rest.replace(/\u00a0/g, ' '));
|
|
450
446
|
return out;
|
|
451
447
|
}
|
|
448
|
+
/**
|
|
449
|
+
* Interner Textdruck: Stil senden (Ausrichtung zuerst), absolute Position
|
|
450
|
+
* setzen (`ESC $`, ausser bei einer vollen Zeile), Bytes ausgeben. [colInd]/
|
|
451
|
+
* [colWidth] beschreiben die Spalte im Zwoelftel-Raster.
|
|
452
|
+
*/
|
|
452
453
|
function textIntern(doc, textBytes, optionen = {}) {
|
|
453
454
|
const stile = vollstaendigeStile(optionen.styles);
|
|
454
455
|
const colInd = optionen.colInd ?? 0;
|
|
455
456
|
const colWidth = optionen.colWidth ?? 12;
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
457
|
+
// Ausrichtung vor Position -- `ESC a` gilt nur am Zeilenanfang, nach `ESC $`
|
|
458
|
+
// verwirft der Drucker ihn. Zwilling von `_text` in generator.dart.
|
|
459
|
+
escPosSetStyles(doc, optionen.styles);
|
|
460
|
+
// Eine volle Zeile beginnt am linken Rand; ein Positionsbefehl dafuer waere
|
|
461
|
+
// nicht nur ueberfluessig, er entwertet die Ausrichtung.
|
|
462
|
+
if (!(colInd === 0 && colWidth === 12)) {
|
|
463
|
+
const breiteJeZeichen = zeichenBreite(doc, stile);
|
|
464
|
+
let von = spaltenPosition(doc, colInd);
|
|
465
|
+
if (colWidth !== 12) {
|
|
466
|
+
const bis = spaltenPosition(doc, colInd + colWidth) - doc.spaceBetweenRows;
|
|
467
|
+
const textLaenge = textBytes.length * breiteJeZeichen;
|
|
468
|
+
if (stile.align === 'right') {
|
|
469
|
+
von = bis - textLaenge;
|
|
470
|
+
}
|
|
471
|
+
else if (stile.align === 'center') {
|
|
472
|
+
von = von + (bis - von) / 2 - textLaenge / 2;
|
|
473
|
+
}
|
|
474
|
+
if (von < 0)
|
|
475
|
+
von = 0;
|
|
466
476
|
}
|
|
467
|
-
|
|
468
|
-
|
|
477
|
+
const position = runden(von);
|
|
478
|
+
anhaengen(doc, [...C_POS, position & 0xff, (position >> 8) & 0xff]);
|
|
469
479
|
}
|
|
470
|
-
const position = runden(von);
|
|
471
|
-
anhaengen(doc, [...C_POS, position & 0xff, (position >> 8) & 0xff]);
|
|
472
|
-
escPosSetStyles(doc, optionen.styles);
|
|
473
480
|
anhaengen(doc, textBytes);
|
|
474
481
|
}
|
|
475
482
|
/**
|
|
@@ -706,13 +713,6 @@ function escPosQrCode(doc, text, options = {}) {
|
|
|
706
713
|
}
|
|
707
714
|
if (drucken)
|
|
708
715
|
anhaengen(doc, qrCodeBytes(text, qrOptionen));
|
|
709
|
-
// Ausrichtung SOFORT zuruecksetzen: `ESC a` gilt nur am Zeilenanfang. Die
|
|
710
|
-
// Spalten-Positionierung (`ESC $`) schickt ihren Reset sonst mitten in der
|
|
711
|
-
// Zeile — Epson ignoriert ihn, und alles nach dem QR rueckte nach rechts
|
|
712
|
-
// (belegt am TM-T20, 2026-08-20).
|
|
713
|
-
if ((options.align ?? 'center') !== 'left') {
|
|
714
|
-
escPosSetStyles(doc, { align: 'left' });
|
|
715
|
-
}
|
|
716
716
|
}
|
|
717
717
|
/**
|
|
718
718
|
* Der Bildweg: ein fertiges QR-Raster als Rasterbild (`GS v 0`) — der
|
|
@@ -770,9 +770,6 @@ function escPosQrRaster(doc, matrix, options = {}) {
|
|
|
770
770
|
anhaengen(doc, rasterBildKopf(breite, breite));
|
|
771
771
|
anhaengen(doc, daten);
|
|
772
772
|
anhaengen(doc, [ZEILENUMBRUCH]);
|
|
773
|
-
if ((options.align ?? 'center') !== 'left') {
|
|
774
|
-
escPosSetStyles(doc, { align: 'left' });
|
|
775
|
-
}
|
|
776
773
|
}
|
|
777
774
|
/**
|
|
778
775
|
* Punkte je Modul, mit denen `escPosQrRaster` ein Raster dieser Groesse auf
|
|
@@ -845,7 +842,4 @@ function escPosRasterBild(doc, bild, options = {}) {
|
|
|
845
842
|
escPosSetStyles(doc, { align: options.align ?? 'center' });
|
|
846
843
|
anhaengen(doc, rasterBildKopf(bild.breite, bild.hoehe));
|
|
847
844
|
anhaengen(doc, daten);
|
|
848
|
-
if ((options.align ?? 'center') !== 'left') {
|
|
849
|
-
escPosSetStyles(doc, { align: 'left' });
|
|
850
|
-
}
|
|
851
845
|
}
|
|
@@ -17,4 +17,5 @@ export { cancelInvoice, createCreditNote, createCustomer, getCustomer, getInvoic
|
|
|
17
17
|
export type { Brand, CancelInvoiceRequest, CancelResult, CreditNoteRequest, CreditNoteResult, Customer, CustomerInput, CustomerPage, CustomerSearch, EInvoiceStatus, Invoice, InvoiceDetail, InvoiceItem, InvoiceItemInput, InvoiceListQuery, InvoicePage, InvoiceRecipient, InvoiceSetupGap, InvoiceSetupStatus, InvoiceTotals, InvoiceNotice, InvoicePayment, InvoicePreview, InvoiceRateTotals, IssueInvoiceRequest, IssueResult, PaymentInput, PreviewResult, RecordPaymentRequest, RecordPaymentResult, } from './typen.js';
|
|
18
18
|
export { RECHNUNG_TEXTE, rechnungText, type RechnungTextSchluessel } from './texte.js';
|
|
19
19
|
export { rechnungSummen, STEUERFREIE_FAELLE, type SummenPosition } from './summen.js';
|
|
20
|
+
export { anteiligerPreis, BETRAG_GRENZE_CENTS, positionAusEuro, preisText, RechenFehler, rechnungRechnen, rund, satzSchluessel, satzText, type RechenErgebnis, type RechenFehlerCode, type RechenOptionen, type RechenPosition, type SatzSumme, type Umwandlung, type UmwandlungsGrund, type ZeilenBetrag, } from './rechnen.js';
|
|
20
21
|
export { RECHNUNG_VERTRAG_VERSION, RECHNUNG_AUFRUFE, INVOICE_ERROR_CODES, CREDIT_NOTE_REASONS, TAX_SCHEMES, PRICE_MODES, VAT_RATES, CUSTOMER_TYPES, INVOICE_LIST_STATUS, DOC_TYPES, EINVOICE_FORMATS, INVOICE_LANGUAGES, INVOICE_PAYMENT_METHODS, ITEM_KINDS, REVERSE_CHARGE_REASONS, INVOICE_NOTICE_CODES, INVOICE_UNITS, RECHNUNG_EINHEITEN_CODES, INVOICE_SETUP_REQUIREMENTS, KUNDE_FELDER, POSITION_FELDER, RECHNUNG_ANFRAGEN, RECHNUNG_GENAU_EINS, RECHNUNG_MINDESTENS_EINS, type RechnungAufruf, type InvoiceErrorCode, type CreditNoteReason, type TaxScheme, type PriceMode, type VatRatePercent, type CustomerType, type InvoiceListStatus, type DocType, type EInvoiceFormat, type InvoiceLanguage, type InvoicePaymentMethod, type ItemKind, type ReverseChargeReason, type InvoiceNoticeCode, type InvoiceUnit, type InvoiceSetupRequirement, type Format, type Feld, } from './vertrag.js';
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
* Benutzung des Clients.
|
|
13
13
|
*/
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.
|
|
15
|
+
exports.INVOICE_UNITS = exports.INVOICE_NOTICE_CODES = exports.REVERSE_CHARGE_REASONS = exports.ITEM_KINDS = 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 = exports.satzText = exports.satzSchluessel = exports.rund = exports.rechnungRechnen = exports.RechenFehler = exports.preisText = exports.positionAusEuro = exports.BETRAG_GRENZE_CENTS = exports.anteiligerPreis = exports.STEUERFREIE_FAELLE = exports.rechnungSummen = exports.rechnungText = exports.RECHNUNG_TEXTE = exports.updateCustomer = exports.searchCustomers = exports.recordInvoicePayment = exports.previewInvoice = exports.listInvoices = exports.listBrands = exports.issueInvoice = exports.getInvoiceXml = exports.getInvoiceSetupStatus = exports.getInvoicePdf = exports.getInvoice = exports.getCustomer = exports.createCustomer = exports.createCreditNote = exports.cancelInvoice = exports.rechnungFeldFehler = exports.rechnungFehlerCode = exports.istRechnungFehler = exports.rechnungKeyAuth = exports.createRechnungApi = void 0;
|
|
16
|
+
exports.RECHNUNG_MINDESTENS_EINS = exports.RECHNUNG_GENAU_EINS = exports.RECHNUNG_ANFRAGEN = exports.POSITION_FELDER = exports.KUNDE_FELDER = exports.INVOICE_SETUP_REQUIREMENTS = exports.RECHNUNG_EINHEITEN_CODES = void 0;
|
|
16
17
|
var api_js_1 = require("./api.js");
|
|
17
18
|
Object.defineProperty(exports, "createRechnungApi", { enumerable: true, get: function () { return api_js_1.createRechnungApi; } });
|
|
18
19
|
var auth_js_1 = require("./auth.js");
|
|
@@ -43,6 +44,16 @@ Object.defineProperty(exports, "rechnungText", { enumerable: true, get: function
|
|
|
43
44
|
var summen_js_1 = require("./summen.js");
|
|
44
45
|
Object.defineProperty(exports, "rechnungSummen", { enumerable: true, get: function () { return summen_js_1.rechnungSummen; } });
|
|
45
46
|
Object.defineProperty(exports, "STEUERFREIE_FAELLE", { enumerable: true, get: function () { return summen_js_1.STEUERFREIE_FAELLE; } });
|
|
47
|
+
var rechnen_js_1 = require("./rechnen.js");
|
|
48
|
+
Object.defineProperty(exports, "anteiligerPreis", { enumerable: true, get: function () { return rechnen_js_1.anteiligerPreis; } });
|
|
49
|
+
Object.defineProperty(exports, "BETRAG_GRENZE_CENTS", { enumerable: true, get: function () { return rechnen_js_1.BETRAG_GRENZE_CENTS; } });
|
|
50
|
+
Object.defineProperty(exports, "positionAusEuro", { enumerable: true, get: function () { return rechnen_js_1.positionAusEuro; } });
|
|
51
|
+
Object.defineProperty(exports, "preisText", { enumerable: true, get: function () { return rechnen_js_1.preisText; } });
|
|
52
|
+
Object.defineProperty(exports, "RechenFehler", { enumerable: true, get: function () { return rechnen_js_1.RechenFehler; } });
|
|
53
|
+
Object.defineProperty(exports, "rechnungRechnen", { enumerable: true, get: function () { return rechnen_js_1.rechnungRechnen; } });
|
|
54
|
+
Object.defineProperty(exports, "rund", { enumerable: true, get: function () { return rechnen_js_1.rund; } });
|
|
55
|
+
Object.defineProperty(exports, "satzSchluessel", { enumerable: true, get: function () { return rechnen_js_1.satzSchluessel; } });
|
|
56
|
+
Object.defineProperty(exports, "satzText", { enumerable: true, get: function () { return rechnen_js_1.satzText; } });
|
|
46
57
|
var vertrag_js_1 = require("./vertrag.js");
|
|
47
58
|
Object.defineProperty(exports, "RECHNUNG_VERTRAG_VERSION", { enumerable: true, get: function () { return vertrag_js_1.RECHNUNG_VERTRAG_VERSION; } });
|
|
48
59
|
Object.defineProperty(exports, "RECHNUNG_AUFRUFE", { enumerable: true, get: function () { return vertrag_js_1.RECHNUNG_AUFRUFE; } });
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Der Rechenkern der Rechnung — exakt, in ganzen Zahlen.
|
|
3
|
+
*
|
|
4
|
+
* Eine Zeile ist ein Bruch: Preis (µ€) × Menge (Tausendstel) × Rabattanteil
|
|
5
|
+
* (Hundertstel-Prozent). Multipliziert man die Skalen, ist die kleinste Einheit
|
|
6
|
+
* 10⁻¹⁷ Cent — das passt in keine Gleitkommazahl und in keine 53-Bit-Ganzzahl,
|
|
7
|
+
* also rechnet der Kern mit BigInt. Gerundet wird genau EINMAL je USt-Satz, auf
|
|
8
|
+
* dem Bruch, kaufmaennisch (halbe Einheit vom Nullpunkt weg).
|
|
9
|
+
*
|
|
10
|
+
* Warum das so streng ist: Vier Umsetzungen (Server, dieses Paket, Dart, Panel)
|
|
11
|
+
* mussten bisher dieselbe Reihenfolge von Gleitkomma-Schritten nachbauen, damit
|
|
12
|
+
* Grenzfaelle gleich runden. Mit Ganzzahlen gibt es keine Reihenfolge mehr, an
|
|
13
|
+
* der etwas auseinanderlaufen koennte.
|
|
14
|
+
*
|
|
15
|
+
* Dieser Unterpfad ist rein: kein Transport, kein Zugangsschluessel, keine
|
|
16
|
+
* Abhaengigkeit ausser Typen. Er wird im Browser gebuendelt (Panel) und im
|
|
17
|
+
* Server geladen.
|
|
18
|
+
*
|
|
19
|
+
* Spec: docs/specs/2026-09-17-rechnung-ganzzahlen-design.md § 5.
|
|
20
|
+
*/
|
|
21
|
+
import type { PriceMode, TaxScheme } from './vertrag.js';
|
|
22
|
+
/** Hoechster Betrag je Zeile und je Rechnung: 999.999.999,99 €. */
|
|
23
|
+
export declare const BETRAG_GRENZE_CENTS = 99999999999;
|
|
24
|
+
/** Steuerfaelle, in denen die Rechnung keine Steuer ausweist: jede Zeile zaehlt zu 0 %. */
|
|
25
|
+
export declare const STEUERFREIE_FAELLE: readonly TaxScheme[];
|
|
26
|
+
/** Eine Position in gespeicherter Form — alle Werte ganzzahlig. */
|
|
27
|
+
export interface RechenPosition {
|
|
28
|
+
/** Einzelpreis in Millionstel Euro, 0 … 10¹². */
|
|
29
|
+
unitPriceMicros: number;
|
|
30
|
+
/** Menge in Tausendstel; negativ = Abzugszeile, 0 = Textzeile. */
|
|
31
|
+
quantityMilli: number;
|
|
32
|
+
/** Rabatt in Hundertstel-Prozent, 0 … 10000 (ohne Angabe 0). */
|
|
33
|
+
discountBp?: number;
|
|
34
|
+
/** USt-Satz in Hundertstel-Prozent, 0 … 10000 (ohne Angabe 0). */
|
|
35
|
+
vatRateBp?: number;
|
|
36
|
+
}
|
|
37
|
+
export interface RechenOptionen {
|
|
38
|
+
priceMode: PriceMode;
|
|
39
|
+
/** Ohne Angabe `normal`. */
|
|
40
|
+
taxScheme?: TaxScheme;
|
|
41
|
+
}
|
|
42
|
+
export interface SatzSumme {
|
|
43
|
+
rateBp: number;
|
|
44
|
+
netCents: number;
|
|
45
|
+
vatCents: number;
|
|
46
|
+
grossCents: number;
|
|
47
|
+
}
|
|
48
|
+
export interface ZeilenBetrag {
|
|
49
|
+
netCents: number;
|
|
50
|
+
grossCents: number;
|
|
51
|
+
/** Der Satz, mit dem die Zeile gerechnet wurde (bei steuerfreiem Fall 0). */
|
|
52
|
+
rateBp: number;
|
|
53
|
+
}
|
|
54
|
+
export interface RechenErgebnis {
|
|
55
|
+
netCents: number;
|
|
56
|
+
vatCents: number;
|
|
57
|
+
grossCents: number;
|
|
58
|
+
/** Absteigend nach `rateBp`. */
|
|
59
|
+
byRate: SatzSumme[];
|
|
60
|
+
/** Je Position, in der Reihenfolge der Eingabe. */
|
|
61
|
+
lines: ZeilenBetrag[];
|
|
62
|
+
}
|
|
63
|
+
export type RechenFehlerCode = 'amount_too_large' | 'kein_ganzzahlwert' | 'ausserhalb';
|
|
64
|
+
/** Fehler des Kerns — mit Code, Feld und Index, damit die API daraus einen Feldfehler machen kann. */
|
|
65
|
+
export declare class RechenFehler extends Error {
|
|
66
|
+
readonly code: RechenFehlerCode;
|
|
67
|
+
readonly feld?: string;
|
|
68
|
+
readonly index?: number;
|
|
69
|
+
constructor(code: RechenFehlerCode, nachricht: string, feld?: string, index?: number);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* `a / b` kaufmaennisch gerundet, halbe Einheit vom Nullpunkt weg; `b` > 0.
|
|
73
|
+
*
|
|
74
|
+
* Ohne Gleitkomma: `(2·|a| + b) / (2·b)` ist genau dann eins groesser, wenn der
|
|
75
|
+
* Rest mindestens die halbe Einheit betraegt.
|
|
76
|
+
*/
|
|
77
|
+
export declare function rund(a: bigint, b: bigint): bigint;
|
|
78
|
+
export declare function rechnungRechnen(positionen: readonly RechenPosition[], optionen: RechenOptionen): RechenErgebnis;
|
|
79
|
+
export type UmwandlungsGrund = 'kein_zahlwert' | 'nachkommastellen' | 'ausserhalb';
|
|
80
|
+
export type Umwandlung = {
|
|
81
|
+
ok: true;
|
|
82
|
+
position: RechenPosition & Record<string, unknown>;
|
|
83
|
+
} | {
|
|
84
|
+
ok: false;
|
|
85
|
+
feld: 'unitPrice' | 'quantity' | 'vatRate' | 'discountPct';
|
|
86
|
+
grund: UmwandlungsGrund;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Euro-Position → Ganzzahl-Form, verlustfrei oder mit Grund abgelehnt. Die
|
|
90
|
+
* EINE Stelle, die das tut: Panel (beim Lesen), SEPA-Lauf, Umrechnungsskript
|
|
91
|
+
* und das Festschreiben benutzen alle diese Funktion, damit niemand eine
|
|
92
|
+
* zweite Auslegung baut.
|
|
93
|
+
*
|
|
94
|
+
* Eine Position, die schon `unitPriceMicros` traegt, kommt unveraendert
|
|
95
|
+
* zurueck — die Funktion ist die Formweiche, nicht eine blinde Umrechnung.
|
|
96
|
+
*
|
|
97
|
+
* Fehlende Menge und fehlender Satz gelten als 0, weil der Server bisher so
|
|
98
|
+
* abgerechnet hat. Ein fehlender Preis dagegen ist NIE 0: sonst wuerde eine
|
|
99
|
+
* Position, der nur der Preis fehlt, still zur 0-€-Zeile.
|
|
100
|
+
*/
|
|
101
|
+
export declare function positionAusEuro(item: Record<string, unknown>): Umwandlung;
|
|
102
|
+
/**
|
|
103
|
+
* Anteiliger Preis fuer einen Teilzeitraum (erste Rechnung eines Abos).
|
|
104
|
+
* War der Ursprungspreis centgenau, bleibt auch der Anteil centgenau — sonst
|
|
105
|
+
* stuende auf der ersten Rechnung ein Preis mit sechs Stellen, wo bisher zwei
|
|
106
|
+
* standen.
|
|
107
|
+
*/
|
|
108
|
+
export declare function anteiligerPreis(unitPriceMicros: number, monate: number, intervall: number): number;
|
|
109
|
+
/**
|
|
110
|
+
* Schluessel eines USt-Satzes in den gespeicherten Maps (`creditedCents.byRate`,
|
|
111
|
+
* `invoice_stats.vatByRate`): der Prozenttext mit Punkt, genau wie
|
|
112
|
+
* `String(satz)` ihn bisher gebildet hat. NICHT fuer die Anzeige — dafuer gibt
|
|
113
|
+
* es `satzText`.
|
|
114
|
+
*/
|
|
115
|
+
export declare function satzSchluessel(rateBp: number): string;
|
|
116
|
+
/** Ein USt-Satz fuer die Anzeige: oesterreichisch mit Komma, ohne nachlaufende Nullen. */
|
|
117
|
+
export declare function satzText(rateBp: number): string;
|
|
118
|
+
/**
|
|
119
|
+
* Ein Einzelpreis fuer die Anzeige: mindestens zwei, hoechstens sechs
|
|
120
|
+
* Nachkommastellen, Tausenderpunkt, Komma als Trennzeichen — in jeder Sprache
|
|
121
|
+
* oesterreichisch, wie die Betraege auf dem Blatt.
|
|
122
|
+
*/
|
|
123
|
+
export declare function preisText(unitPriceMicros: number): string;
|