Files
mareike/CLAUDE.md
T
2026-08-11 16:01:00 +02:00

4.3 KiB
Raw Blame History

CLAUDE.md

Laravel 12 + Inertia/Vue, mandantenfähig (custom tenant-Scoping über app('tenant'), gesetzt in app/Middleware/IdentifyTenant.php). PHP 8.5 — Tests/Artisan laufen im Container: docker exec mareike-mareike-app-1 php artisan test.

Projektkonventionen (verbindlich)

Die verbindlichen Konventionen (Actions/Request-Command-Response, Controller, Repositories, Models/Resources, Tenant, Routing, Mails) stehen in .ai/conventions.md und werden hier eingebunden — immer beachten:

@.ai/conventions.md

Bereichs-Dokumentation

  • Zahlungsmodule — interface-gesteuerte Zahlungsarten (Optionen, Config, Anmelde-Zusammenfassung, GiroCode/Fähigkeits-Interfaces, neues Modul hinzufügen).

Umsatzsteuer / Steuerinformationen

Rechtlich korrekter Begriff ist Umsatzsteuer (USt), nicht MwSt. Ziel: tagesbasierte Anmelde-Rechnungen („Teilnahme Veranstaltung X in Gruppe Y" × Anwesenheitstage × Beitrag/Tag). Grundlage ist gebaut, die Rechnungs-PDF/-berechnung folgt noch.

Tenant-Einstellungen (Tab „Steuerinformationen")

Felder auf tenants (Self-Service TenantData.vue + verwaltet TenantEdit.vue, Partial TenantTaxInfo.vue, Controller TenantTax* / ManagedTenantTax*, Action UpdateTenantTax):

  • tax_liable (bool) — ob USt-Pflicht besteht.
  • vat_rate (int, %) — USt-Satz, nur relevant wenn tax_liable (0100, geclamped).
  • vat_pricing_mode (Enum App\Enumerations\VatPricingMode, natives PHP-Enum: inclusive | add_on).
  • tax_exemption_reason (FK → tax_exemption_reasons.slug, nullable) — Grund wenn nicht steuerpflichtig. DB-Default neuer Tenants: ustg_4_25a (Jugendhilfe).
  • tax_exemption_note (text, nullable) — Freitext, nur bei Grund custom (requires_note).

Preismodus — das Kernverhalten

Es wird immer der finale Brutto-Beitrag pro Anmeldung gespeichert (EventParticipant.amount, keine USt-Spalten am Teilnehmer). Der Modus wirkt nur bei der Preisermittlung im Anmeldeprozess:

  • inclusive (Brutto / „zusammenfassen", Supermarkt-Prinzip, Default): der konfigurierte Beitrag ist der Endpreis, USt ist bereits enthalten → Preis bleibt gleich; die USt wird erst auf der Rechnung herausgerechnet: USt = brutto × Satz / (100 + Satz), netto = brutto USt.
  • add_on (Netto / „aufaddieren"): der konfigurierte Beitrag ist netto → Endpreis = Beitrag × (1 + Satz/100). Die USt wird bei der Anmeldung aufgeschlagen → Teilnehmer zahlt mehr.

Umsetzung in App\Resources\EventResource::calculateAmount(): nach allen Multiplikatoren (Early-Bird, pay_per_day, Geschwister) gilt if ($event->tax_liable && $event->vat_pricing_mode === VatPricingMode::AddOn->value) $fee->multiply(1 + $event->vat_rate/100); danach round(…, 2). Bei inclusive/nicht steuerpflichtig bleibt der Beitrag unverändert.

Event-Snapshot (unveränderlich)

Bei Event-Anlage (CreateEventCommand::execute()) werden tax_liable, vat_rate, vat_pricing_mode, tax_exemption_reason, tax_exemption_note aus dem Tenant auf das Event kopiert und dort eingefroren (Spalten auf events). Preisermittlung und spätere Rechnungen lesen vom Event, nicht vom Tenant → spätere Tenant-Änderungen berühren bestehende Events/Rechnungen nicht.

Befreiungsgründe (DB-gestützt)

Tabelle tax_exemption_reasons, Model App\Enumerations\TaxExemptionReason (Eloquent, slug PK; name, invoice_text, requires_note, sort_order). options() liefert {value,label,text} sortiert nach sort_order. FK von tenants und events. Seed in Migration 170010, verfeinert in 170020. Gründe (in Reihenfolge): ustg_19 (§ 19 Kleinunternehmer), ustg_4_24 (§ 4 Nr. 24 Jugendherbergen), ustg_4_25a (§ 4 Nr. 25 Buchst. a — Jugendhilfe-Veranstaltungen, Default), ustg_4_22a (§ 4 Nr. 22 Buchst. a — Vorträge/Kurse), custom (Freitext). Jeder Grund kapselt den Rechnungs-Pflichthinweis nach § 14 Abs. 4 Nr. 8 UStG (invoice_text; bei custom der Tenant-Freitext via invoiceText(?note)). Gemeinnützigkeit allein befreit nicht — es braucht immer einen konkreten Rechtsgrund.

Noch offen (nächster Schritt)

Die eigentliche Rechnung: tagesbasierte Positionen, USt aus dem gespeicherten Brutto herausrechnen (Satz vom Event-Snapshot); bei Befreiung kein USt-Ausweis, stattdessen der Pflichthinweis des Grundes.