""" Datenmodell – Templates, Jobs, Log-Einträge. """ import uuid from pathlib import Path from django.conf import settings from django.db import models def template_upload_path(instance, filename: str) -> str: return f"templates/{instance.id}/{Path(filename).name}" def csv_upload_path(instance, filename: str) -> str: return f"jobs/{instance.id}/recipients/{Path(filename).name}" def result_upload_path(instance, filename: str) -> str: return f"jobs/{instance.id}/result/{Path(filename).name}" class LetterTemplate(models.Model): """DOCX-Vorlage mit Jinja-Platzhaltern.""" id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField(max_length=200) description = models.TextField(blank=True) file = models.FileField(upload_to=template_upload_path) placeholders = models.JSONField(default=list, blank=True, help_text="Aus dem DOCX extrahierte Variablen.") created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, related_name="templates") created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ["-created_at"] def __str__(self) -> str: return self.name class MailMergeJob(models.Model): class Status(models.TextChoices): PENDING = "pending", "Wartet" RUNNING = "running", "Läuft" DONE = "done", "Fertig" FAILED = "failed", "Fehlgeschlagen" id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) template = models.ForeignKey(LetterTemplate, on_delete=models.PROTECT, related_name="jobs") recipients_csv = models.FileField(upload_to=csv_upload_path) status = models.CharField(max_length=20, choices=Status.choices, default=Status.PENDING) result_pdf = models.FileField(upload_to=result_upload_path, null=True, blank=True) total_rows = models.PositiveIntegerField(default=0) processed_rows = models.PositiveIntegerField(default=0) error_message = models.TextField(blank=True) created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, related_name="jobs") created_at = models.DateTimeField(auto_now_add=True) started_at = models.DateTimeField(null=True, blank=True) finished_at = models.DateTimeField(null=True, blank=True) class Meta: ordering = ["-created_at"] def __str__(self) -> str: return f"Job {self.id} ({self.template.name})" class JobLogEntry(models.Model): class Level(models.TextChoices): INFO = "info", "Info" WARNING = "warning", "Warnung" ERROR = "error", "Fehler" job = models.ForeignKey(MailMergeJob, on_delete=models.CASCADE, related_name="logs") level = models.CharField(max_length=10, choices=Level.choices, default=Level.INFO) message = models.TextField() timestamp = models.DateTimeField(auto_now_add=True) class Meta: ordering = ["timestamp"]