130 lines
4.3 KiB
Python
130 lines
4.3 KiB
Python
"""operation: валюта, расчётная сумма, связь со строкой файла; типы UWFEE, ADJ
|
||
|
||
Revision ID: 7c2e5a9d1f30
|
||
Revises: 3b9f1c2a7d41
|
||
Create Date: 2026-10-19 00:00:00
|
||
|
||
Запись операций из QUIK и ручной ввод (D20, D21, D22). Таблица operation до
|
||
этой ревизии не заполнялась, поэтому currency_id сразу NOT NULL.
|
||
"""
|
||
|
||
from typing import Sequence, Union
|
||
|
||
import sqlalchemy as sa
|
||
|
||
from alembic import op
|
||
from app.core.config import settings
|
||
|
||
# revision identifiers, used by Alembic.
|
||
revision: str = "7c2e5a9d1f30"
|
||
down_revision: Union[str, None] = "3b9f1c2a7d41"
|
||
branch_labels: Union[str, Sequence[str], None] = None
|
||
depends_on: Union[str, Sequence[str], None] = None
|
||
|
||
_schema = settings.DATABASE_SCHEMA or None
|
||
|
||
# Типы зафиксированы в ревизии, как и в начальной миграции.
|
||
_AMOUNT = sa.Numeric(20, 6)
|
||
_SEED_USER = "system"
|
||
_NEW_TYPES = [
|
||
("UWFEE", "Комиссия за андеррайтинг"),
|
||
("ADJ", "Корректировка"),
|
||
]
|
||
|
||
|
||
def _trade_number_index(create: bool) -> None:
|
||
# В SQLite batch пересоздаёт таблицу и теряет WHERE частичного индекса —
|
||
# снимаем его на время batch и создаём заново.
|
||
if create:
|
||
op.create_index(
|
||
"ux_operation_portfolio_trade_number",
|
||
"operation",
|
||
["portfolio_id", "trade_number"],
|
||
unique=True,
|
||
schema=_schema,
|
||
postgresql_where=sa.text("trade_number IS NOT NULL"),
|
||
sqlite_where=sa.text("trade_number IS NOT NULL"),
|
||
)
|
||
else:
|
||
op.drop_index(
|
||
"ux_operation_portfolio_trade_number",
|
||
table_name="operation",
|
||
schema=_schema,
|
||
)
|
||
|
||
|
||
def upgrade() -> None:
|
||
"""Upgrade schema."""
|
||
_trade_number_index(create=False)
|
||
with op.batch_alter_table("operation", schema=_schema) as batch:
|
||
batch.add_column(sa.Column("currency_id", sa.BigInteger(), nullable=False))
|
||
batch.add_column(sa.Column("settlement_amount", _AMOUNT, nullable=True))
|
||
batch.add_column(sa.Column("source_row", sa.Integer(), nullable=True))
|
||
batch.create_foreign_key(
|
||
"fk_operation_currency",
|
||
"currency",
|
||
["currency_id"],
|
||
["id"],
|
||
referent_schema=_schema,
|
||
)
|
||
batch.create_foreign_key(
|
||
"fk_operation_import_batch",
|
||
"import_batch",
|
||
["import_batch_id"],
|
||
["id"],
|
||
referent_schema=_schema,
|
||
)
|
||
batch.create_unique_constraint(
|
||
"uq_operation_batch_row", ["import_batch_id", "source_row"]
|
||
)
|
||
_trade_number_index(create=True)
|
||
op.create_index(
|
||
"ix_operation_portfolio_security_date",
|
||
"operation",
|
||
["portfolio_id", "security_id", "trade_date"],
|
||
schema=_schema,
|
||
)
|
||
|
||
operation_type = sa.table(
|
||
"operation_type",
|
||
sa.column("code", sa.String),
|
||
sa.column("name", sa.String),
|
||
sa.column("created_by", sa.String),
|
||
sa.column("updated_by", sa.String),
|
||
schema=_schema,
|
||
)
|
||
op.bulk_insert(
|
||
operation_type,
|
||
[
|
||
{
|
||
"code": code,
|
||
"name": name,
|
||
"created_by": _SEED_USER,
|
||
"updated_by": _SEED_USER,
|
||
}
|
||
for code, name in _NEW_TYPES
|
||
],
|
||
)
|
||
|
||
|
||
def downgrade() -> None:
|
||
"""Downgrade schema."""
|
||
codes = ", ".join(f"'{code}'" for code, _ in _NEW_TYPES)
|
||
table = f"{_schema}.operation_type" if _schema else "operation_type"
|
||
op.execute(f"DELETE FROM {table} WHERE code IN ({codes})")
|
||
|
||
op.drop_index(
|
||
"ix_operation_portfolio_security_date",
|
||
table_name="operation",
|
||
schema=_schema,
|
||
)
|
||
_trade_number_index(create=False)
|
||
with op.batch_alter_table("operation", schema=_schema) as batch:
|
||
batch.drop_constraint("uq_operation_batch_row", type_="unique")
|
||
batch.drop_constraint("fk_operation_import_batch", type_="foreignkey")
|
||
batch.drop_constraint("fk_operation_currency", type_="foreignkey")
|
||
batch.drop_column("source_row")
|
||
batch.drop_column("settlement_amount")
|
||
batch.drop_column("currency_id")
|
||
_trade_number_index(create=True)
|