from django.core.validators import RegexValidator from django.db import models from django.db.models import Q from .base import IdentifiedModel class SourceRecord(IdentifiedModel): class Format(models.TextChoices): BANK_CSV = "BANK_CSV", "Bank CSV" OUROCARD_TXT = "OUROCARD_TXT", "Ourocard TXT" transaction = models.ForeignKey("finance.Transaction", on_delete=models.PROTECT, related_name="source_records") document_hash = models.CharField(max_length=64, validators=[ RegexValidator(r"\A[0-9a-f]{64}\Z", "Use a lowercase SHA-256 hexadecimal digest.")]) source_format = models.CharField(max_length=16, choices=Format.choices) parser_version = models.CharField(max_length=128) item_locator = models.CharField(max_length=255) class Meta: constraints = [ models.CheckConstraint(condition=Q(source_format__in=["BANK_CSV", "OUROCARD_TXT"]), name="source_valid_format"), models.CheckConstraint(condition=Q(document_hash__regex=r"^[0-9a-f]{64}$"), name="source_valid_hash"), models.CheckConstraint(condition=Q(parser_version__regex=r"\S"), name="source_nonblank_parser"), models.CheckConstraint(condition=Q(item_locator__regex=r"\S"), name="source_nonblank_locator"), models.UniqueConstraint(fields=["document_hash", "item_locator"], name="source_document_item_unique"), ] class AuditEvent(IdentifiedModel): class ActorKind(models.TextChoices): HUMAN = "HUMAN", "Human" APPLICATION = "APPLICATION", "Application" AGENT = "AGENT", "Agent" class Outcome(models.TextChoices): SUCCESS = "SUCCESS", "Success" FAILURE = "FAILURE", "Failure" actor_kind = models.CharField(max_length=16, choices=ActorKind.choices) actor_identifier = models.CharField(max_length=255) operation = models.CharField(max_length=128) target_id = models.UUIDField(null=True, blank=True) outcome = models.CharField(max_length=16, choices=Outcome.choices) changed_fields = models.JSONField(default=list, blank=True) error_code = models.CharField(max_length=128, blank=True) class Meta: constraints = [ models.CheckConstraint(condition=Q(actor_kind__in=["HUMAN", "APPLICATION", "AGENT"]), name="audit_valid_actor"), models.CheckConstraint(condition=Q(outcome__in=["SUCCESS", "FAILURE"]), name="audit_valid_outcome"), models.CheckConstraint(condition=Q(actor_identifier__regex=r"\S"), name="audit_nonblank_actor"), models.CheckConstraint(condition=Q(operation__regex=r"\S"), name="audit_nonblank_operation"), ]