"""Add invoices and invoice_lines tables. Revision ID: 042 Revises: 041 """ import sqlalchemy as sa from alembic import op from sqlalchemy.dialects.postgresql import UUID revision = '042' down_revision = '041' branch_labels = None depends_on = None def upgrade(): op.create_table( 'invoices', sa.Column('id', UUID(as_uuid=True), primary_key=True, server_default=sa.text('gen_random_uuid()')), sa.Column('tenant_id', UUID(as_uuid=True), sa.ForeignKey('tenants.id', ondelete='CASCADE'), nullable=True), sa.Column('invoice_number', sa.String(20), nullable=False, unique=True), sa.Column('status', sa.String(20), nullable=False, server_default='draft'), sa.Column('issued_at', sa.Date, nullable=True), sa.Column('due_at', sa.Date, nullable=True), sa.Column('total_net', sa.Numeric(12, 2), nullable=True), sa.Column('total_vat', sa.Numeric(12, 2), nullable=True), sa.Column('vat_rate', sa.Numeric(5, 4), nullable=False, server_default='0.19'), sa.Column('currency', sa.String(3), nullable=False, server_default='EUR'), sa.Column('notes', sa.Text, nullable=True), sa.Column('pdf_key', sa.Text, nullable=True), sa.Column('created_at', sa.DateTime, nullable=False, server_default=sa.text('NOW()')), sa.Column('updated_at', sa.DateTime, nullable=False, server_default=sa.text('NOW()')), ) op.create_index('ix_invoices_tenant', 'invoices', ['tenant_id']) op.create_index('ix_invoices_status', 'invoices', ['status']) op.create_table( 'invoice_lines', sa.Column('id', UUID(as_uuid=True), primary_key=True, server_default=sa.text('gen_random_uuid()')), sa.Column('invoice_id', UUID(as_uuid=True), sa.ForeignKey('invoices.id', ondelete='CASCADE'), nullable=False), sa.Column('order_line_id', UUID(as_uuid=True), sa.ForeignKey('order_lines.id', ondelete='SET NULL'), nullable=True), sa.Column('description', sa.Text, nullable=False), sa.Column('quantity', sa.Integer, nullable=False, server_default='1'), sa.Column('unit_price', sa.Numeric(10, 2), nullable=True), sa.Column('total', sa.Numeric(10, 2), nullable=True), ) op.create_index('ix_invoice_lines_invoice', 'invoice_lines', ['invoice_id']) # RLS op.execute("ALTER TABLE invoices ENABLE ROW LEVEL SECURITY") op.execute(""" DO $$ BEGIN CREATE POLICY tenant_isolation ON invoices USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid); EXCEPTION WHEN duplicate_object THEN NULL; END $$; """) op.execute(""" DO $$ BEGIN CREATE POLICY admin_bypass ON invoices USING (current_setting('app.current_tenant_id', true) = 'bypass'); EXCEPTION WHEN duplicate_object THEN NULL; END $$; """) def downgrade(): op.drop_table('invoice_lines') op.drop_table('invoices')