models.py (3.496 Zeilen) in 6 Domain-Module aufgeteilt: - system.py: CSVImport, ApplicationPermission, AuditLog, BackupJob, AppConfiguration, HelpBox - land.py: Paechter, Land, LandVerpachtung, LandAbrechnung, DokumentLink - finanzen.py: Rentmeister, StiftungsKonto, BankTransaction, Verwaltungskosten - destinataere.py: Destinataer, Person, Foerderung, DestinataerUnterstuetzung, UnterstuetzungWiederkehrend, DestinataerNotiz, VierteljahresNachweis, DestinataerEmailEingang - veranstaltungen.py: BriefVorlage, Veranstaltung, Veranstaltungsteilnehmer - geschichte.py: GeschichteSeite, GeschichteBild, StiftungsKalenderEintrag __init__.py re-exportiert alle Models für volle Rückwärtskompatibilität. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
214 lines
6.8 KiB
Python
214 lines
6.8 KiB
Python
import uuid
|
|
|
|
from django.db import models
|
|
from django.utils import timezone
|
|
|
|
|
|
class GeschichteSeite(models.Model):
|
|
"""Wiki-style pages for foundation history"""
|
|
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
titel = models.CharField(max_length=200, verbose_name="Titel")
|
|
slug = models.SlugField(max_length=200, unique=True, verbose_name="URL-Slug")
|
|
inhalt = models.TextField(
|
|
verbose_name="Inhalt (Markdown)",
|
|
blank=True,
|
|
help_text="Sie können Markdown verwenden: **fett**, *kursiv*, # Überschriften, [Links](URL), Listen, etc."
|
|
)
|
|
|
|
# Metadata
|
|
erstellt_am = models.DateTimeField(auto_now_add=True, verbose_name="Erstellt am")
|
|
aktualisiert_am = models.DateTimeField(auto_now=True, verbose_name="Aktualisiert am")
|
|
erstellt_von = models.ForeignKey(
|
|
'auth.User',
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
related_name='geschichte_seiten_erstellt',
|
|
verbose_name="Erstellt von"
|
|
)
|
|
aktualisiert_von = models.ForeignKey(
|
|
'auth.User',
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
related_name='geschichte_seiten_aktualisiert',
|
|
verbose_name="Aktualisiert von"
|
|
)
|
|
|
|
# Options
|
|
ist_veroeffentlicht = models.BooleanField(default=True, verbose_name="Veröffentlicht")
|
|
sortierung = models.IntegerField(default=0, verbose_name="Sortierung")
|
|
|
|
class Meta:
|
|
verbose_name = "Geschichte Seite"
|
|
verbose_name_plural = "Geschichte Seiten"
|
|
ordering = ['sortierung', 'titel']
|
|
|
|
def __str__(self):
|
|
return self.titel
|
|
|
|
def get_absolute_url(self):
|
|
from django.urls import reverse
|
|
return reverse('stiftung:geschichte_detail', kwargs={'slug': self.slug})
|
|
|
|
|
|
class GeschichteBild(models.Model):
|
|
"""Images for history pages"""
|
|
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
seite = models.ForeignKey(
|
|
GeschichteSeite,
|
|
on_delete=models.CASCADE,
|
|
related_name='bilder',
|
|
verbose_name="Geschichte Seite"
|
|
)
|
|
titel = models.CharField(max_length=200, verbose_name="Bildtitel")
|
|
bild = models.ImageField(
|
|
upload_to='geschichte/bilder/%Y/%m/',
|
|
verbose_name="Bild"
|
|
)
|
|
beschreibung = models.TextField(blank=True, verbose_name="Beschreibung")
|
|
alt_text = models.CharField(max_length=200, blank=True, verbose_name="Alt-Text")
|
|
|
|
# Metadata
|
|
hochgeladen_am = models.DateTimeField(auto_now_add=True, verbose_name="Hochgeladen am")
|
|
hochgeladen_von = models.ForeignKey(
|
|
'auth.User',
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
verbose_name="Hochgeladen von"
|
|
)
|
|
|
|
sortierung = models.IntegerField(default=0, verbose_name="Sortierung")
|
|
|
|
class Meta:
|
|
verbose_name = "Geschichte Bild"
|
|
verbose_name_plural = "Geschichte Bilder"
|
|
ordering = ['sortierung', 'titel']
|
|
|
|
def __str__(self):
|
|
return f"{self.titel} ({self.seite.titel})"
|
|
|
|
|
|
class StiftungsKalenderEintrag(models.Model):
|
|
"""Custom calendar events for foundation management"""
|
|
|
|
KATEGORIE_CHOICES = [
|
|
('termin', 'Termin/Meeting'),
|
|
('zahlung', 'Zahlungserinnerung'),
|
|
('deadline', 'Frist/Deadline'),
|
|
('geburtstag', 'Geburtstag'),
|
|
('vertrag', 'Vertrag läuft aus'),
|
|
('pruefung', 'Prüfung/Nachweis'),
|
|
('sonstiges', 'Sonstiges'),
|
|
]
|
|
|
|
PRIORITAET_CHOICES = [
|
|
('niedrig', 'Niedrig'),
|
|
('normal', 'Normal'),
|
|
('hoch', 'Hoch'),
|
|
('kritisch', 'Kritisch'),
|
|
]
|
|
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
titel = models.CharField(max_length=200, verbose_name="Titel")
|
|
beschreibung = models.TextField(blank=True, verbose_name="Beschreibung")
|
|
|
|
# Date and time
|
|
datum = models.DateField(verbose_name="Datum")
|
|
uhrzeit = models.TimeField(null=True, blank=True, verbose_name="Uhrzeit")
|
|
ganztags = models.BooleanField(default=True, verbose_name="Ganztägig")
|
|
|
|
# Categorization
|
|
kategorie = models.CharField(
|
|
max_length=20,
|
|
choices=KATEGORIE_CHOICES,
|
|
default='termin',
|
|
verbose_name="Kategorie"
|
|
)
|
|
prioritaet = models.CharField(
|
|
max_length=20,
|
|
choices=PRIORITAET_CHOICES,
|
|
default='normal',
|
|
verbose_name="Priorität"
|
|
)
|
|
|
|
# Links to related objects
|
|
destinataer = models.ForeignKey(
|
|
'stiftung.Destinataer',
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.CASCADE,
|
|
verbose_name="Bezogener Destinatär"
|
|
)
|
|
verpachtung = models.ForeignKey(
|
|
'stiftung.LandVerpachtung',
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.CASCADE,
|
|
verbose_name="Bezogene Verpachtung"
|
|
)
|
|
|
|
# Status and completion
|
|
erledigt = models.BooleanField(default=False, verbose_name="Erledigt")
|
|
erledigt_am = models.DateTimeField(null=True, blank=True, verbose_name="Erledigt am")
|
|
|
|
# Metadata
|
|
erstellt_von = models.CharField(
|
|
max_length=100,
|
|
null=True,
|
|
blank=True,
|
|
verbose_name="Erstellt von"
|
|
)
|
|
erstellt_am = models.DateTimeField(auto_now_add=True, verbose_name="Erstellt am")
|
|
aktualisiert_am = models.DateTimeField(auto_now=True, verbose_name="Aktualisiert am")
|
|
|
|
class Meta:
|
|
verbose_name = "Kalender Eintrag"
|
|
verbose_name_plural = "Kalender Einträge"
|
|
ordering = ['datum', 'uhrzeit']
|
|
indexes = [
|
|
models.Index(fields=['datum']),
|
|
models.Index(fields=['kategorie', 'datum']),
|
|
models.Index(fields=['erledigt', 'datum']),
|
|
]
|
|
|
|
def __str__(self):
|
|
return f"{self.datum}: {self.titel}"
|
|
|
|
def get_kategorie_icon(self):
|
|
icons = {
|
|
'termin': 'fas fa-calendar-alt',
|
|
'zahlung': 'fas fa-euro-sign',
|
|
'deadline': 'fas fa-exclamation-triangle',
|
|
'geburtstag': 'fas fa-birthday-cake',
|
|
'vertrag': 'fas fa-file-contract',
|
|
'pruefung': 'fas fa-clipboard-check',
|
|
'sonstiges': 'fas fa-calendar',
|
|
}
|
|
return icons.get(self.kategorie, 'fas fa-calendar')
|
|
|
|
def get_prioritaet_color(self):
|
|
colors = {
|
|
'niedrig': 'success',
|
|
'normal': 'primary',
|
|
'hoch': 'warning',
|
|
'kritisch': 'danger',
|
|
}
|
|
return colors.get(self.prioritaet, 'primary')
|
|
|
|
def is_overdue(self):
|
|
"""Check if event is overdue (past due and not completed)"""
|
|
if self.erledigt:
|
|
return False
|
|
return self.datum < timezone.now().date()
|
|
|
|
def is_upcoming(self, days=7):
|
|
"""Check if event is upcoming within specified days"""
|
|
if self.erledigt:
|
|
return False
|
|
today = timezone.now().date()
|
|
return today <= self.datum <= (today + timezone.timedelta(days=days))
|