mirror of
https://github.com/idrainformatica/PecFlow.git
synced 2026-06-16 12:45:42 +02:00
153 lines
4.5 KiB
Python
153 lines
4.5 KiB
Python
"""
|
||
Router scadenzario e tracking deadlines (Feature 4).
|
||
|
||
Endpoint:
|
||
GET /deadlines – messaggi con scadenze imminenti
|
||
POST /messages/{id}/deadline – imposta/modifica/rimuove scadenza
|
||
"""
|
||
|
||
import uuid
|
||
from datetime import datetime, timedelta, timezone
|
||
|
||
from fastapi import APIRouter, Query
|
||
from pydantic import BaseModel
|
||
from sqlalchemy import and_, select
|
||
|
||
from app.dependencies import CurrentUser, DB
|
||
from app.models.message import Message
|
||
from app.schemas.message import MessageResponse
|
||
from app.core.exceptions import NotFoundError
|
||
|
||
router = APIRouter(tags=["Deadlines"])
|
||
|
||
|
||
class DeadlineSetRequest(BaseModel):
|
||
deadline_at: datetime | None = None
|
||
"""Imposta a null per rimuovere la scadenza."""
|
||
deadline_note: str | None = None
|
||
|
||
|
||
class DeadlineMessageResponse(BaseModel):
|
||
model_config = {"from_attributes": True}
|
||
|
||
id: uuid.UUID
|
||
subject: str | None
|
||
from_address: str | None
|
||
to_addresses: list[str] | None = None
|
||
direction: str
|
||
pec_type: str
|
||
state: str
|
||
mailbox_id: uuid.UUID
|
||
deadline_at: datetime | None = None
|
||
deadline_note: str | None = None
|
||
is_overdue: bool = False
|
||
received_at: datetime | None = None
|
||
sent_at: datetime | None = None
|
||
created_at: datetime
|
||
|
||
|
||
@router.get("/deadlines", response_model=list[DeadlineMessageResponse])
|
||
async def list_deadlines(
|
||
current_user: CurrentUser,
|
||
db: DB,
|
||
days_ahead: int = Query(30, ge=1, le=365, description="Giorni da considerare in avanti"),
|
||
include_overdue: bool = Query(True, description="Includi scadenze gia' passate"),
|
||
) -> list[DeadlineMessageResponse]:
|
||
"""
|
||
Restituisce i messaggi con scadenze nel range specificato.
|
||
|
||
Ordinati per: scaduti prima, poi per deadline_at ASC.
|
||
"""
|
||
now = datetime.now(timezone.utc)
|
||
future_limit = now + timedelta(days=days_ahead)
|
||
|
||
conditions = [
|
||
Message.tenant_id == current_user.tenant_id,
|
||
Message.deadline_at.is_not(None),
|
||
Message.is_trashed == False, # noqa: E712
|
||
]
|
||
|
||
if include_overdue:
|
||
# Include scaduti e futuri fino al limite
|
||
conditions.append(Message.deadline_at <= future_limit)
|
||
else:
|
||
# Solo scadenze future
|
||
conditions.append(and_(Message.deadline_at > now, Message.deadline_at <= future_limit))
|
||
|
||
result = await db.execute(
|
||
select(Message)
|
||
.where(and_(*conditions))
|
||
.order_by(Message.deadline_at)
|
||
.limit(200)
|
||
)
|
||
messages = list(result.scalars().all())
|
||
|
||
items = []
|
||
for msg in messages:
|
||
is_overdue = msg.deadline_at < now if msg.deadline_at else False
|
||
items.append(DeadlineMessageResponse(
|
||
id=msg.id,
|
||
subject=msg.subject,
|
||
from_address=msg.from_address,
|
||
to_addresses=msg.to_addresses,
|
||
direction=msg.direction,
|
||
pec_type=msg.pec_type,
|
||
state=msg.state,
|
||
mailbox_id=msg.mailbox_id,
|
||
deadline_at=msg.deadline_at,
|
||
deadline_note=msg.deadline_note,
|
||
is_overdue=is_overdue,
|
||
received_at=msg.received_at,
|
||
sent_at=msg.sent_at,
|
||
created_at=msg.created_at,
|
||
))
|
||
return items
|
||
|
||
|
||
@router.post("/messages/{message_id}/deadline", response_model=DeadlineMessageResponse)
|
||
async def set_deadline(
|
||
message_id: uuid.UUID,
|
||
data: DeadlineSetRequest,
|
||
current_user: CurrentUser,
|
||
db: DB,
|
||
) -> DeadlineMessageResponse:
|
||
"""
|
||
Imposta, modifica o rimuove la scadenza di un messaggio.
|
||
|
||
Passa deadline_at=null per rimuovere la scadenza.
|
||
"""
|
||
result = await db.execute(
|
||
select(Message).where(
|
||
Message.id == message_id,
|
||
Message.tenant_id == current_user.tenant_id,
|
||
)
|
||
)
|
||
msg = result.scalar_one_or_none()
|
||
if not msg:
|
||
raise NotFoundError(f"Messaggio {message_id} non trovato")
|
||
|
||
msg.deadline_at = data.deadline_at
|
||
msg.deadline_note = data.deadline_note
|
||
await db.commit()
|
||
await db.refresh(msg)
|
||
|
||
now = datetime.now(timezone.utc)
|
||
is_overdue = msg.deadline_at < now if msg.deadline_at else False
|
||
|
||
return DeadlineMessageResponse(
|
||
id=msg.id,
|
||
subject=msg.subject,
|
||
from_address=msg.from_address,
|
||
to_addresses=msg.to_addresses,
|
||
direction=msg.direction,
|
||
pec_type=msg.pec_type,
|
||
state=msg.state,
|
||
mailbox_id=msg.mailbox_id,
|
||
deadline_at=msg.deadline_at,
|
||
deadline_note=msg.deadline_note,
|
||
is_overdue=is_overdue,
|
||
received_at=msg.received_at,
|
||
sent_at=msg.sent_at,
|
||
created_at=msg.created_at,
|
||
)
|