mirror of
https://github.com/idrainformatica/PecFlow.git
synced 2026-06-16 12:45:42 +02:00
OCR + reportistica
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
"""
|
||||
Schemi Pydantic per la Dashboard e Reportistica (Fase 7).
|
||||
"""
|
||||
|
||||
from datetime import date, datetime
|
||||
from typing import Optional
|
||||
import uuid
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class KpiSummary(BaseModel):
|
||||
"""Contatori KPI principali del tenant."""
|
||||
|
||||
# Oggi
|
||||
received_today: int = Field(0, description="PEC ricevute oggi")
|
||||
sent_today: int = Field(0, description="PEC inviate oggi (outbound)")
|
||||
|
||||
# Ultimi 7 giorni
|
||||
received_7d: int = Field(0, description="PEC ricevute negli ultimi 7 giorni")
|
||||
sent_7d: int = Field(0, description="PEC inviate negli ultimi 7 giorni")
|
||||
|
||||
# Ultimi 30 giorni
|
||||
received_30d: int = Field(0, description="PEC ricevute negli ultimi 30 giorni")
|
||||
sent_30d: int = Field(0, description="PEC inviate negli ultimi 30 giorni")
|
||||
|
||||
# Stato
|
||||
anomalie_attive: int = Field(0, description="Messaggi outbound in stato anomaly")
|
||||
tasso_consegna: float = Field(0.0, description="Percentuale consegna (0-100)")
|
||||
caselle_in_errore: int = Field(0, description="Caselle con status=error")
|
||||
messaggi_non_letti: int = Field(0, description="Messaggi inbound non letti")
|
||||
|
||||
# Totali assoluti
|
||||
totale_messaggi: int = Field(0, description="Totale messaggi nel tenant")
|
||||
|
||||
|
||||
class DailyStat(BaseModel):
|
||||
"""Statistiche giornaliere per il grafico a barre."""
|
||||
|
||||
day: date = Field(..., description="Data (YYYY-MM-DD)")
|
||||
received: int = Field(0, description="PEC ricevute in quel giorno")
|
||||
sent: int = Field(0, description="PEC inviate in quel giorno")
|
||||
|
||||
|
||||
class OutboundStateStat(BaseModel):
|
||||
"""Conteggio messaggi outbound per stato (per il grafico a torta)."""
|
||||
|
||||
state: str
|
||||
count: int
|
||||
|
||||
|
||||
class MailboxStat(BaseModel):
|
||||
"""Statistiche per singola casella."""
|
||||
|
||||
mailbox_id: uuid.UUID
|
||||
email_address: str
|
||||
display_name: Optional[str] = None
|
||||
status: str
|
||||
received_total: int = 0
|
||||
sent_total: int = 0
|
||||
anomalie: int = 0
|
||||
non_letti: int = 0
|
||||
last_sync_at: Optional[datetime] = None
|
||||
|
||||
|
||||
class ReportSummaryResponse(BaseModel):
|
||||
"""Risposta completa dell'endpoint /reports/summary."""
|
||||
|
||||
generated_at: datetime
|
||||
period_days: int = Field(..., description="Numero di giorni del periodo selezionato")
|
||||
|
||||
kpi: KpiSummary
|
||||
daily_stats: list[DailyStat] = Field(default_factory=list)
|
||||
outbound_states: list[OutboundStateStat] = Field(default_factory=list)
|
||||
mailbox_stats: list[MailboxStat] = Field(default_factory=list)
|
||||
@@ -1,12 +1,13 @@
|
||||
"""
|
||||
Schema Pydantic per TenantSettings – lettura e aggiornamento impostazioni tenant.
|
||||
Include schemi per il modulo di indicizzazione full-text.
|
||||
"""
|
||||
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Literal
|
||||
from typing import Literal, Optional
|
||||
|
||||
from pydantic import BaseModel, Field, HttpUrl, field_validator
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
|
||||
|
||||
ArchivalMode = Literal["mock", "production"]
|
||||
@@ -68,3 +69,53 @@ class TenantSettingsUpdate(BaseModel):
|
||||
if v is not None and v not in ("mock", "production"):
|
||||
raise ValueError("archival_mode deve essere 'mock' o 'production'")
|
||||
return v
|
||||
|
||||
|
||||
# ─── Schemi indicizzazione full-text ──────────────────────────────────────────
|
||||
|
||||
class IndexingStats(BaseModel):
|
||||
"""Statistiche di copertura dell'indicizzazione per un tenant."""
|
||||
|
||||
total_messages: int
|
||||
indexed_messages: int
|
||||
unindexed_messages: int
|
||||
coverage_pct: float # percentuale messaggi con search_vector != NULL
|
||||
|
||||
attachments_total: int # allegati PDF/DOCX totali
|
||||
attachments_extracted: int # allegati con testo estratto
|
||||
attachments_pct: float # percentuale allegati con testo estratto
|
||||
|
||||
|
||||
class IndexingJobStatus(BaseModel):
|
||||
"""Stato di un job di reindex in corso o completato."""
|
||||
|
||||
status: str # idle | running | completed | failed | cancelled
|
||||
mode: Optional[str] = None # full | differential
|
||||
total: int = 0
|
||||
processed: int = 0
|
||||
progress_pct: float = 0.0
|
||||
|
||||
started_at: Optional[str] = None # ISO datetime
|
||||
finished_at: Optional[str] = None # ISO datetime
|
||||
started_by: Optional[str] = None # email utente che ha avviato il job
|
||||
elapsed_seconds: Optional[int] = None
|
||||
is_stale: bool = False # True se running da piu' di STALE_THRESHOLD_HOURS
|
||||
error: Optional[str] = None
|
||||
|
||||
|
||||
class StartReindexRequest(BaseModel):
|
||||
"""Body per POST /settings/indexing/reindex."""
|
||||
|
||||
mode: Literal["full", "differential"] = "differential"
|
||||
|
||||
|
||||
class StartRescanRequest(BaseModel):
|
||||
"""Body per POST /settings/indexing/rescan."""
|
||||
|
||||
force: bool = Field(
|
||||
default=False,
|
||||
description=(
|
||||
"False (default): estrae solo allegati con extracted_text NULL. "
|
||||
"True: ri-estrae tutti gli allegati, sovrascrivendo i testi gia' presenti."
|
||||
),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user