c-stone-invoice-check/backend/models.py

103 lines
3.6 KiB
Python

"""
C-Stone Invoice Check — Datenbankmodelle
SQLAlchemy ORM Modelle für Rechnungen und Emails
"""
from datetime import datetime
from sqlalchemy import Column, Integer, String, DateTime, Float, Boolean, Text, JSON
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Invoice(Base):
"""
Tabelle: Rechnungen
Speichert die Metadaten jeder verarbeiteten Rechnung
"""
__tablename__ = "invoices"
id = Column(Integer, primary_key=True, index=True)
email_id = Column(String, index=True) # IMAP UID der Original-Email
email_subject = Column(String, nullable=True)
email_from = Column(String, nullable=True)
email_date = Column(DateTime, nullable=True)
# Rechnungsdaten
invoice_number = Column(String, index=True, nullable=True)
invoice_date = Column(DateTime, nullable=True)
invoice_amount = Column(Float, nullable=True)
invoice_tax_amount = Column(Float, nullable=True)
invoice_tax_rate = Column(Float, nullable=True) # z.B. 0, 0.19, 0.16
invoice_tax_type = Column(String, nullable=True) # "MwSt", "Umsatzsteuer", "VAT", "ohne"
# Absender/Empfänger
issuer_name = Column(String, nullable=True)
issuer_address = Column(Text, nullable=True)
# Dateipfad (Evo-X2)
file_path = Column(String, nullable=True)
file_name = Column(String, nullable=True)
storage_year = Column(Integer, nullable=True)
storage_path = Column(String, nullable=True) # z.B. "2025/ohne MwSt"
# Verarbeitungsstatus
processed = Column(Boolean, default=False)
processing_error = Column(Text, nullable=True)
confidence_score = Column(Float, nullable=True) # 0.0 - 1.0
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def __repr__(self):
return f"<Invoice {self.invoice_number or 'unknown'}>"
class EmailLog(Base):
"""
Tabelle: Email Logs
Protokolliert jede verarbeitete Email
"""
__tablename__ = "email_logs"
id = Column(Integer, primary_key=True, index=True)
email_id = Column(String, unique=True, index=True) # IMAP UID
email_subject = Column(String, nullable=True)
email_from = Column(String, nullable=True)
email_date = Column(DateTime, nullable=True)
email_folder = Column(String, nullable=True) # z.B. "INBOX", "Gesendet"
# Filterergebnis
matched_keywords = Column(JSON, nullable=True) # Liste von Stichworten
has_attachment = Column(Boolean, default=False)
attachment_type = Column(String, nullable=True) # "pdf", "doc", "docx", "unknown"
# Verarbeitung
processed = Column(Boolean, default=False)
processing_result = Column(String, nullable=True) # "invoice_found", "not_an_invoice", "error"
invoice_id = Column(Integer, nullable=True) # Verweis auf Invoice-Tabelle
created_at = Column(DateTime, default=datetime.utcnow)
def __repr__(self):
return f"<EmailLog {self.email_id}>"
class InvoiceDetail(Base):
"""
Tabelle: Rechnungsdetails (erweiterte Informationen)
Speichert JSON-basierte erweiterte Daten
"""
__tablename__ = "invoice_details"
id = Column(Integer, primary_key=True, index=True)
invoice_id = Column(Integer, nullable=False, index=True)
raw_text = Column(Text, nullable=True) # Extrahierter PDF-Text
parsed_data = Column(JSON, nullable=True) # Geparste Daten als JSON
confidence_breakdown = Column(JSON, nullable=True) # Einzelne Confidence-Scores
processing_notes = Column(Text, nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
def __repr__(self):
return f"<InvoiceDetail {self.invoice_id}>"