""" Modelli Archival – versamenti verso conservatore AgID. """ import uuid from datetime import date, datetime from sqlalchemy import ( CHAR, DateTime, Enum, ForeignKey, Index, Integer, String, Text, func, ) from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column from app.database import Base ArchivalStatus = Enum( "pending", "building_sip", "uploading", "uploaded", "confirmed", "rejected", "failed", name="archival_status", create_type=False, ) class ArchivalBatch(Base): __tablename__ = "archival_batches" id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=uuid.uuid4 ) tenant_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False ) conservatore_id: Mapped[str] = mapped_column(String(100), nullable=False) status: Mapped[str] = mapped_column(ArchivalStatus, nullable=False, default="pending") sip_path: Mapped[str | None] = mapped_column(Text, nullable=True) sip_checksum: Mapped[str | None] = mapped_column(CHAR(64), nullable=True) versamento_id: Mapped[str | None] = mapped_column(Text, nullable=True) rdv_received_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) rdv_path: Mapped[str | None] = mapped_column(Text, nullable=True) rdv_checksum: Mapped[str | None] = mapped_column(CHAR(64), nullable=True) attempt_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0) max_attempts: Mapped[int] = mapped_column(Integer, nullable=False, default=3) next_retry_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) last_error: Mapped[str | None] = mapped_column(Text, nullable=True) period_from: Mapped[date] = mapped_column(nullable=False) period_to: Mapped[date] = mapped_column(nullable=False) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now() ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now() ) __table_args__ = ( Index("idx_archival_tenant", "tenant_id"), Index("idx_archival_status", "status", "next_retry_at"), ) class ArchivalBatchMessage(Base): __tablename__ = "archival_batch_messages" batch_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("archival_batches.id", ondelete="CASCADE"), primary_key=True, ) message_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("messages.id", ondelete="CASCADE"), primary_key=True, ) class ArchivalDip(Base): __tablename__ = "archival_dips" id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=uuid.uuid4 ) tenant_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False ) batch_id: Mapped[uuid.UUID | None] = mapped_column( UUID(as_uuid=True), ForeignKey("archival_batches.id"), nullable=True ) requested_by: Mapped[uuid.UUID | None] = mapped_column( UUID(as_uuid=True), ForeignKey("users.id"), nullable=True ) dip_path: Mapped[str | None] = mapped_column(Text, nullable=True) status: Mapped[str] = mapped_column(String(50), nullable=False, default="requested") requested_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now() ) received_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)