feat: Haben-clone + client portal privacy fix
Client Portal privacy (şirket sırrı): - Removed PRD references from client-facing text - Removed 'Projekt-isolierter Zugriff' technical term - Changed to 'Sichere Verbindung' / 'Sicher geschützt' - Onboarding overlay only shows to agency users (not portal) Haben-cloned features (Almanya/EU muhasebe uyumu): - Belege: content-addressed receipts (SHA-256 hash, GoBD retention 8/6 years) - Pauschalen: Homeoffice (€6.92/day), Kilometer (€0.30/km), Verpflegung (€14/€24/€28) - EStG § 4 Abs. 5, § 9 Abs. 1 compliant rates (2026) - Anlagen & AfA: Anlagenverzeichnis with linear depreciation - GWG (≤€800 Sofortabschreibung, § 6 Abs. 2 EStG) - Sammelposten (€251-€1000, § 6 Abs. 2a EStG, 5 years) - Annual AfA computation + accumulated AfA + book value - Kassenbuch: cash book (§ 146 AO, § 22 UStG) - Immutable (GoBD), running balance, audit-logged - Gapless numbering (KAS-2026-XXXX) Seed data: 5 Belege, 7 Pauschalen, 5 Anlagen, 5 Kassenbuch entries TypeScript: 0 errors | ESLint: clean
This commit is contained in:
1 parent
3cb7532417
commit
1573931c0f
13 files changed
+2234
-5
No files matched your search
@@ -568,6 +568,106 @@ model Article {
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Haben-cloned features: Belege, Pauschalen, Anlagen/AfA, Kasse
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Belege (receipts/documents) — content-addressed storage (PRD §5.5)
|
||||
model Beleg {
|
||||
id String @id @default(cuid())
|
||||
number String @unique // gapless, e.g. BEL-2026-0001
|
||||
type String // rechnung-eingang|rechnung-ausgang|quittung|kassenbeleg|bankbeleg|sonstiges
|
||||
// content-addressed (SHA-256 hash of the file content)
|
||||
fileHash String @unique
|
||||
fileName String
|
||||
fileType String // application/pdf, image/jpeg, etc.
|
||||
fileSizeBytes Int
|
||||
// metadata extracted from the document
|
||||
vendor String? // Rechnungssteller
|
||||
invoiceNumber String? // Rechnungsnummer des Lieferanten
|
||||
amountCents Int? // Bruttobetrag auf dem Beleg
|
||||
amountNetCents Int? // Netto (falls extrahiert)
|
||||
taxBp Int? // USt %
|
||||
bookingDate DateTime?
|
||||
// linking
|
||||
expenseId String? // link to Expense if billable
|
||||
invoiceId String? // link to Invoice if outgoing
|
||||
// OCR / AI
|
||||
ocrText String? // extracted text (optional, via Jina/AI)
|
||||
// GoBD
|
||||
archivedAt DateTime?
|
||||
retentionUntil DateTime? // Aufbewahrung bis
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
||||
// Pauschalen (flat-rate allowances) — Homeoffice, Kilometer, Verpflegung
|
||||
model Pauschale {
|
||||
id String @id @default(cuid())
|
||||
type String // homeoffice|kilometer|verpflegung
|
||||
// homeoffice: €4.17/day (2026: €6.92/day up to €1.260/year)
|
||||
// kilometer: €0.30/km (car), €0.38/km (car w/ pass), or actual
|
||||
// verpflegung: €14 (8-14h), €24 (>14h, same day), €28 (overnight)
|
||||
date DateTime
|
||||
userId String? // employee
|
||||
amountCents Int // computed amount
|
||||
// details per type
|
||||
days Int? // homeoffice: 1; verpflegung: 1
|
||||
km Int? // kilometer: distance
|
||||
vehicleType String? // kilometer: auto|rad|fuss
|
||||
tripPurpose String? // kilometer: geschäftlich|fortbildung|umzug
|
||||
hoursAway Int? // verpflegung: hours away from office
|
||||
overnight Boolean @default(false) // verpflegung: overnight stay
|
||||
description String?
|
||||
projectId String? // link to project if billable
|
||||
expenseId String? // link to generated expense
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
||||
// Anlagenverzeichnis & AfA (asset register + depreciation)
|
||||
model Anlage {
|
||||
id String @id @default(cuid())
|
||||
number String @unique // e.g. ANL-2026-0001
|
||||
name String // "MacBook Pro 16"
|
||||
category String // hardware|software|mobiliar|fahrzeug|immobilie
|
||||
// acquisition
|
||||
purchaseDate DateTime
|
||||
purchaseCostCents Int // Anschaffungskosten (netto)
|
||||
taxBp Int @default(1900) // USt bei Anschaffung
|
||||
// AfA (depreciation)
|
||||
afaMethod String @default("linear") // linear|degressiv
|
||||
usefulLifeYears Int @default(3) // Nutzungsdauer (AfA-Tabelle)
|
||||
salvageValueCents Int @default(0) // Restwert
|
||||
// GWG (Geringwertiger Wirtschaftsgüter ≤ €800 net → Sofortabschreibung)
|
||||
isGWG Boolean @default(false) // GWG ≤ €800 → immediate expense
|
||||
// Sammelposten (€251-€1000 → Sammelabschreibung über 5 Jahre)
|
||||
isSammelposten Boolean @default(false)
|
||||
// computed
|
||||
annualAfaCents Int @default(0) // jährliche AfA
|
||||
accumulatedAfaCents Int @default(0) // kumulierte AfA
|
||||
bookValueCents Int @default(0) // Buchwert (purchase - accumulated AfA)
|
||||
// status
|
||||
status String @default("active") // active|sold|scrapped|fully-depreciated
|
||||
soldDate DateTime?
|
||||
soldPriceCents Int?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
// Kassenbuch (cash book for Barzahlungen — § 146 AO, § 22 UStG)
|
||||
model KassenbuchEntry {
|
||||
id String @id @default(cuid())
|
||||
number String @unique // gapless, e.g. KAS-2026-0001
|
||||
date DateTime
|
||||
type String // einnahme|ausgabe
|
||||
description String
|
||||
amountCents Int // signed: + for einnahme, - for ausgabe
|
||||
taxBp Int? // USt % (if applicable)
|
||||
taxFree Boolean @default(false) // steuerfrei
|
||||
// receipt link
|
||||
belegId String? // link to Beleg (Kassenbeleg)
|
||||
// balance after this entry (laufender Kassenstand)
|
||||
balanceCents Int @default(0)
|
||||
// GoBD: Kassenbuch ist unveränderlich (elektronische Aufzeichnung)
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user