"""Add inventory_transactions table Revision ID: o3c4d5e6f7a8 Revises: n2c3d4e5f6a7 Create Date: 2026-01-01 Adds an audit trail for inventory movements: - Track all stock changes (reserve, fulfill, release, adjust, set) - Link transactions to orders for traceability - Store quantity snapshots for historical analysis """ from alembic import op import sqlalchemy as sa # revision identifiers, used by Alembic. revision = "o3c4d5e6f7a8" down_revision = "n2c3d4e5f6a7" branch_labels = None depends_on = None def upgrade() -> None: # Create transaction type enum transaction_type_enum = sa.Enum( "reserve", "fulfill", "release", "adjust", "set", "import", "return", name="transactiontype", ) op.create_table( "inventory_transactions", sa.Column("id", sa.Integer(), nullable=False), sa.Column("vendor_id", sa.Integer(), nullable=False), sa.Column("product_id", sa.Integer(), nullable=False), sa.Column("inventory_id", sa.Integer(), nullable=True), sa.Column("transaction_type", transaction_type_enum, nullable=False), sa.Column("quantity_change", sa.Integer(), nullable=False), sa.Column("quantity_after", sa.Integer(), nullable=False), sa.Column("reserved_after", sa.Integer(), nullable=False, server_default="0"), sa.Column("location", sa.String(), nullable=True), sa.Column("warehouse", sa.String(), nullable=True), sa.Column("order_id", sa.Integer(), nullable=True), sa.Column("order_number", sa.String(), nullable=True), sa.Column("reason", sa.Text(), nullable=True), sa.Column("created_by", sa.String(), nullable=True), sa.Column( "created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now(), ), sa.ForeignKeyConstraint(["vendor_id"], ["vendors.id"]), sa.ForeignKeyConstraint(["product_id"], ["products.id"]), sa.ForeignKeyConstraint(["inventory_id"], ["inventory.id"]), sa.ForeignKeyConstraint(["order_id"], ["orders.id"]), sa.PrimaryKeyConstraint("id"), ) # Create indexes op.create_index( "ix_inventory_transactions_id", "inventory_transactions", ["id"], ) op.create_index( "ix_inventory_transactions_vendor_id", "inventory_transactions", ["vendor_id"], ) op.create_index( "ix_inventory_transactions_product_id", "inventory_transactions", ["product_id"], ) op.create_index( "ix_inventory_transactions_inventory_id", "inventory_transactions", ["inventory_id"], ) op.create_index( "ix_inventory_transactions_transaction_type", "inventory_transactions", ["transaction_type"], ) op.create_index( "ix_inventory_transactions_order_id", "inventory_transactions", ["order_id"], ) op.create_index( "ix_inventory_transactions_created_at", "inventory_transactions", ["created_at"], ) op.create_index( "idx_inv_tx_vendor_product", "inventory_transactions", ["vendor_id", "product_id"], ) op.create_index( "idx_inv_tx_vendor_created", "inventory_transactions", ["vendor_id", "created_at"], ) op.create_index( "idx_inv_tx_type_created", "inventory_transactions", ["transaction_type", "created_at"], ) def downgrade() -> None: op.drop_index("idx_inv_tx_type_created", table_name="inventory_transactions") op.drop_index("idx_inv_tx_vendor_created", table_name="inventory_transactions") op.drop_index("idx_inv_tx_vendor_product", table_name="inventory_transactions") op.drop_index( "ix_inventory_transactions_created_at", table_name="inventory_transactions" ) op.drop_index( "ix_inventory_transactions_order_id", table_name="inventory_transactions" ) op.drop_index( "ix_inventory_transactions_transaction_type", table_name="inventory_transactions" ) op.drop_index( "ix_inventory_transactions_inventory_id", table_name="inventory_transactions" ) op.drop_index( "ix_inventory_transactions_product_id", table_name="inventory_transactions" ) op.drop_index( "ix_inventory_transactions_vendor_id", table_name="inventory_transactions" ) op.drop_index("ix_inventory_transactions_id", table_name="inventory_transactions") op.drop_table("inventory_transactions") # Drop enum sa.Enum(name="transactiontype").drop(op.get_bind(), checkfirst=True)