from __future__ import annotations from datetime import date from sqlalchemy import BigInteger, Date, ForeignKey, Integer, String, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column from app.core.config import settings from app.db.base import Base from app.db.types import AuditMixin, IdMixin, JsonType, qualified class ImportBatch(IdMixin, AuditMixin, Base): """Загрузка файла сделок в портфель (D19). Защита от повтора — на уровне файла: (content_sha256, portfolio_id) уникальны. Хэш — по нормализованным строкам (app/imports/quik.py), поэтому пересохранённый в Excel файл с теми же данными — тоже повтор. rows_total — непустых строк в файле; rows_loaded — загружено в этот портфель; rows_excluded — строк без портфеля (пустой/неизвестный комментарий, /trde), которые пользователь явно исключил. Остальное — строки другого портфеля или уже загруженные из этого файла туда. loaded_rows — порядковые номера загруженных строк (QuikTrade.ordinal): по ним видно, какие строки файла не загружены никуда. """ __tablename__ = "import_batch" __table_args__ = ( UniqueConstraint( "content_sha256", "portfolio_id", name="uq_import_batch_content_portfolio" ), {"schema": settings.DATABASE_SCHEMA} if settings.DATABASE_SCHEMA else {}, ) source: Mapped[str] = mapped_column(String(10), nullable=False) portfolio_id: Mapped[int] = mapped_column( BigInteger, ForeignKey(qualified("portfolio.id")), nullable=False ) file_name: Mapped[str] = mapped_column(String(255), nullable=False) content_sha256: Mapped[str] = mapped_column(String(64), nullable=False) date_from: Mapped[date] = mapped_column(Date, nullable=False) date_to: Mapped[date] = mapped_column(Date, nullable=False) rows_total: Mapped[int] = mapped_column(Integer, nullable=False) rows_loaded: Mapped[int] = mapped_column(Integer, nullable=False) rows_excluded: Mapped[int] = mapped_column(Integer, nullable=False) loaded_rows: Mapped[list[int]] = mapped_column(JsonType, nullable=False)