Money Type
Status: Offen
Bedarf aus den Samples
| Sample | Entity | Felder |
|---|---|---|
| mietnomade | lease | baseRent, prepayment, heatingPrepayment, totalRent, deposit |
| mietnomade | billingItem | totalAmount |
| mietnomade | billing.calculate | unitShare, tenantShare, amount, totalCosts, totalPrepaid, balance |
| beammycar | order | buyingPrice, sellingPrice |
| beammycar | invoiceLine | priceNet |
| beammycar | invoice | totalNet, totalVat, totalGross |
Muster
- Waehrung: Beide Samples sind EUR-only (Deutschland). Multi-Currency ist kein Muss
- Praezision: 2 Dezimalstellen reichen fuer Mieten/Preise. NKA braucht evtl. mehr Zwischenpraezision
- Berechnungen: totalRent = baseRent + prepayment + heatingPrepayment (serverseitig)
- Anzeige: Formatierung (1.234,56 EUR) ist UI-Sache, nicht DB-Sache
Aktueller Stand
number Feld-Typ mapped zu integer in der DB. Kein Decimal-Support.
Weg A: Eigener money Feld-Typ (Cents als Integer)
Geld wird als Integer in Cents gespeichert. 12,50 EUR = 1250. Formatierung ist UI-Logik.
API
r.entity("lease", { fields: { baseRent: { type: "money", required: true }, // → DB: integer (cents) prepayment: { type: "money", required: true }, deposit: { type: "money" }, },});DB
base_rent INTEGER NOT NULL, -- 1250 = 12,50 EURprepayment INTEGER NOT NULL,deposit INTEGERZod
z.number().int() // Input/Output immer in CentsBerechnungen
// Im Handler — alles Integer-Arithmetikconst totalRent = baseRent + prepayment + heatingPrepayment; // 120000 + 15000 + 8000 = 143000Vorteile
- Keine Floating-Point-Fehler — 0.1 + 0.2 !== 0.3 Problem existiert nicht
- Einfach: Integer-Arithmetik, kein Runden noetig bei Addition/Subtraktion
- DB-Dialect-agnostisch: Integer gibt es ueberall
- Sortierung/Vergleich: Funktioniert wie bei normalen Zahlen
- Standard-Pattern: Stripe, Shopify, die meisten Payment-APIs arbeiten mit Cents
Nachteile
- Division braucht Rundung: 10000 / 3 = 3333.33… → Math.round(10000 / 3) = 3333 (0,01 Cent Differenz)
- NKA-Berechnung: Anteilige Berechnung (area-Anteil) erzeugt Rundungsdifferenzen → Cent-Ausgleich noetig
- API-Contract: Client muss wissen dass 1250 = 12,50 EUR ist
- Keine Waehrung gespeichert: Wenn spaeter Multi-Currency → zweites Feld noetig
Weg B: numeric Feld-Typ (Decimal in DB)
Geld wird als Decimal mit fester Praezision gespeichert. DB nutzt NUMERIC(12,2).
API
r.entity("lease", { fields: { baseRent: { type: "money", precision: 2, required: true }, // → DB: NUMERIC(12,2) prepayment: { type: "money", precision: 2, required: true }, deposit: { type: "money", precision: 2 }, },});DB
base_rent NUMERIC(12,2) NOT NULL, -- 12.50prepayment NUMERIC(12,2) NOT NULL,deposit NUMERIC(12,2)Zod
z.number() // oder z.string() fuer exakte Decimal-Darstellung// Achtung: JS number hat Floating-Point — 0.1 + 0.2 !== 0.3JS-Seitige Praezision
// Option 1: String-basiert (sicher aber umstaendlich)const totalRent = "1200.00"; // String → kein Floating-Point Problem
// Option 2: Number mit Runden (pragmatisch)const totalRent = Math.round((baseRent + prepayment) * 100) / 100;
// Option 3: Decimal.js Library (exakt aber Dependency)import { Decimal } from "decimal.js";const totalRent = new Decimal(baseRent).plus(prepayment);Vorteile
- DB rechnet exakt:
SELECT SUM(base_rent) FROM leasesliefert exaktes Ergebnis - Natuerliche Darstellung: 12.50 nicht 1250
- Praezision konfigurierbar: precision: 4 fuer Zwischenberechnungen, precision: 2 fuer Endbetraege
- Multi-Currency ready: Verschiedene Waehrungen brauchen verschiedene Praezision (JPY = 0, BHD = 3)
Nachteile
- JS Floating-Point: Drizzle liefert
numberzurueck → Praezisionsverlust moeglich - Oder String: Drizzle kann NUMERIC als String liefern → alle Berechnungen mit Strings oder Decimal.js
- Dependency: Decimal.js oder aehnliche Library noetig fuer exakte JS-Berechnungen
- DB-Dialect: SQLite hat kein echtes NUMERIC (wird REAL → Floating Point)
- Komplexer: Mehr Code, mehr Edge Cases
Vergleich
| Kriterium | Weg A (Cents/Integer) | Weg B (Decimal) |
|---|---|---|
| Floating-Point sicher | Ja (Integer) | DB ja, JS nein (ohne Library) |
| Einfachheit | Sehr einfach | Komplex (String/Decimal.js) |
| DB-Dialect | Ueberall | Nur PG/MySQL (SQLite: REAL) |
| Berechnungen in JS | Integer-Arithmetik | Library noetig |
| API-Contract | 1250 = 12.50 EUR | 12.50 = 12.50 EUR |
| NKA Rundung | Cent-Ausgleich noetig | Cent-Ausgleich noetig |
| Multi-Currency | Zweites Feld | precision anpassbar |
| Sortierung/Aggregation | Trivial | Trivial |
Anforderungen aus den Samples
- Addition/Subtraktion (totalRent = base + NK + Heizung)
- Division mit Rundung (NKA: Gesamtkosten / Flaeche * Einheit-Flaeche)
- Vergleich (balance > 0 → Nachzahlung)
- Aggregation (SUM ueber billingItems)
- Formatierung (1.234,56 EUR) — UI-seitig, nicht Framework
Empfehlung
Weg A (Cents/Integer) fuer den Start. Deckt beide Samples ab, keine Dependencies, kein Floating-Point-Risiko, DB-Dialect-agnostisch. NKA-Rundungsdifferenzen existieren bei beiden Wegen und werden im Handler geloest (Cent-Ausgleich auf groesste Position).
Wenn spaeter Multi-Currency oder DB-seitige Aggregation mit Praezision > 2 gebraucht wird → Weg B nachrüsten.