Skip to content

Money Type

Status: Offen

Bedarf aus den Samples

SampleEntityFelder
mietnomadeleasebaseRent, prepayment, heatingPrepayment, totalRent, deposit
mietnomadebillingItemtotalAmount
mietnomadebilling.calculateunitShare, tenantShare, amount, totalCosts, totalPrepaid, balance
beammycarorderbuyingPrice, sellingPrice
beammycarinvoiceLinepriceNet
beammycarinvoicetotalNet, 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 EUR
prepayment INTEGER NOT NULL,
deposit INTEGER

Zod

z.number().int() // Input/Output immer in Cents

Berechnungen

// Im Handler — alles Integer-Arithmetik
const totalRent = baseRent + prepayment + heatingPrepayment; // 120000 + 15000 + 8000 = 143000

Vorteile

  • 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.50
prepayment 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.3

JS-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 leases liefert 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 number zurueck → 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

KriteriumWeg A (Cents/Integer)Weg B (Decimal)
Floating-Point sicherJa (Integer)DB ja, JS nein (ohne Library)
EinfachheitSehr einfachKomplex (String/Decimal.js)
DB-DialectUeberallNur PG/MySQL (SQLite: REAL)
Berechnungen in JSInteger-ArithmetikLibrary noetig
API-Contract1250 = 12.50 EUR12.50 = 12.50 EUR
NKA RundungCent-Ausgleich noetigCent-Ausgleich noetig
Multi-CurrencyZweites Feldprecision anpassbar
Sortierung/AggregationTrivialTrivial

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.