"""initial schema — tables and sequences Revision ID: 0001 Revises: Create Date: 2026-06-22 """ from alembic import op import sqlalchemy as sa from sqlalchemy.dialects import postgresql revision = "0001" down_revision = None branch_labels = None depends_on = None def create_table_if_not_exists(table_name, *columns, **kwargs): conn = op.get_bind() inspector = sa.inspect(conn) if table_name not in inspector.get_table_names(schema="v3"): op.create_table(table_name, *columns, **kwargs) return True return False def create_index_if_not_exists(index_name, table_name, columns, **kwargs): conn = op.get_bind() inspector = sa.inspect(conn) existing_indexes = inspector.get_indexes(table_name, schema="v3") if not any(idx['name'] == index_name for idx in existing_indexes): op.create_index(index_name, table_name, columns, **kwargs) return True return False def create_check_constraint_if_not_exists( constraint_name, table_name, condition, schema=None, ): conn = op.get_bind() inspector = sa.inspect(conn) existing_constraints = inspector.get_check_constraints( table_name, schema=schema, ) constraint_exists = any( c['name'] == constraint_name for c in existing_constraints ) if not constraint_exists: op.create_check_constraint( constraint_name, table_name, condition, schema=schema, ) return True else: return False def create_unique_constraint_if_not_exists( constraint_name, table_name, columns, schema=None, ): conn = op.get_bind() inspector = sa.inspect(conn) existing_constraints = inspector.get_unique_constraints( table_name, schema=schema, ) constraint_exists = any( c['name'] == constraint_name for c in existing_constraints ) if not constraint_exists: op.create_unique_constraint( constraint_name, table_name, columns, schema=schema, ) return True else: return False def upgrade() -> None: op.execute("CREATE SCHEMA IF NOT EXISTS v3") create_table_if_not_exists( 'allocation', sa.Column('line_id', sa.Integer(), primary_key=True), sa.Column('internal_order', sa.String()), sa.Column('property_object', sa.String()), sa.Column('contract_ref', sa.String()), sa.Column('allocation_purpose', sa.String()), schema='v3', ) create_table_if_not_exists( 'app_user', sa.Column('id', sa.Integer(), primary_key=True), sa.Column('email', sa.String(), nullable=False), sa.Column('username', sa.String(), nullable=False), sa.Column('hashed_password', sa.String(), nullable=False), sa.Column('full_name', sa.String()), sa.Column('role_id', sa.Integer(), nullable=False), sa.Column('is_active', sa.Boolean(), nullable=False), sa.Column('created_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), sa.Column('updated_at', sa.DateTime(timezone=True)), schema='v3', ) create_index_if_not_exists( 'ix_v4_app_user_active', 'app_user', ['is_active'], schema='v3', postgresql_where='is_active', ) create_index_if_not_exists( 'ix_v4_app_user_role', 'app_user', ['role_id'], schema='v3', ) create_table_if_not_exists( 'audit_log', sa.Column('id', sa.BigInteger(), primary_key=True, autoincrement=True), sa.Column('user_id', sa.Integer()), sa.Column('org_unit_id', sa.Integer()), sa.Column('task_id', sa.Integer()), sa.Column('form_id', sa.Integer()), sa.Column('event_dt', sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), sa.Column('event', sa.String(), nullable=False), sa.Column('event_type', sa.String(), nullable=False), sa.Column('event_data', sa.JSON()), schema='v3', ) create_index_if_not_exists( 'ix_v3_audit_log_form', 'audit_log', ['form_id'], schema='v3', postgresql_where='form_id IS NOT NULL', ) create_index_if_not_exists( 'ix_v3_audit_log_event', 'audit_log', ['event'], schema='v3', ) create_index_if_not_exists( 'ix_v4_audit_log_dt', 'audit_log', ['event_dt'], postgresql_ops={'event_dt': 'DESC'}, schema='v3', ) create_index_if_not_exists( 'ix_v4_audit_log_event', 'audit_log', ['event'], schema='v3', ) create_index_if_not_exists( 'ix_v4_audit_log_form', 'audit_log', ['form_id'], schema='v3', postgresql_where='form_id IS NOT NULL', ) create_index_if_not_exists( 'ix_v3_audit_log_user', 'audit_log', ['user_id'], schema='v3', ) create_index_if_not_exists( 'ix_v4_audit_log_user', 'audit_log', ['user_id'], schema='v3', ) create_index_if_not_exists( 'ix_v3_audit_log_dt', 'audit_log', ['event_dt'], postgresql_ops={'event_dt': 'DESC'}, schema='v3', ) create_table_if_not_exists( 'booking', sa.Column('id', sa.Integer(), primary_key=True), sa.Column('line_id', sa.Integer(), nullable=False), sa.Column('quarter', sa.SmallInteger(), nullable=False), sa.Column('source', sa.String(), nullable=False), sa.Column('booked_amount_ckk', sa.Numeric()), sa.Column('booked_amount_contract', sa.Numeric()), schema='v3', ) create_check_constraint_if_not_exists( 'ck_v3_booking_quarter', 'booking', sa.text('quarter BETWEEN 1 AND 4'), schema='v3', ) create_check_constraint_if_not_exists( 'ck_v3_booking_source', 'booking', sa.text("source IN ('CKK','CONTRACT')"), schema='v3', ) create_index_if_not_exists( 'ix_v3_booking_line', 'booking', ['line_id'], schema='v3', ) create_table_if_not_exists( 'budget_form', sa.Column('id', sa.Integer(), primary_key=True), sa.Column('form_type_code', sa.String(), nullable=False), sa.Column('year', sa.Integer()), sa.Column('created_by', sa.Integer()), sa.Column('created_at', sa.DateTime(), server_default=sa.func.now() ), sa.Column('updated_by', sa.Integer()), sa.Column('updated_at', sa.DateTime(), server_default=sa.func.now(), onupdate=sa.func.now(), ), sa.Column('org_unit_id', sa.Integer()), schema='v3', ) create_table_if_not_exists( 'budget_line', sa.Column('id', sa.Integer(), primary_key=True), sa.Column('budget_form_id', sa.Integer(), nullable=False), sa.Column('expense_item_id', sa.Integer()), sa.Column('name', sa.String()), sa.Column('internal_order', sa.String()), sa.Column('vsp_id', sa.Integer()), sa.Column('project_id', sa.Integer()), sa.Column('justification', sa.String()), sa.Column('created_by', sa.Integer()), sa.Column('created_at', sa.DateTime()), sa.Column('updated_by', sa.Integer()), sa.Column('updated_at', sa.DateTime()), sa.Column('direction', sa.String()), schema='v3', ) create_index_if_not_exists( 'ix_v3_budget_line_vsp', 'budget_line', ['vsp_id'], schema='v3', ) create_index_if_not_exists( 'ix_v3_budget_line_form_item', 'budget_line', ['budget_form_id', 'expense_item_id'], schema='v3', ) create_table_if_not_exists( 'budget_line_quarter', sa.Column('line_id', sa.Integer(), primary_key=True), sa.Column('quarter', sa.SmallInteger(), primary_key=True), sa.Column('adj_current', sa.Numeric()), sa.Column('adj_ssp', sa.Numeric()), sa.Column('adj_rf', sa.Numeric()), sa.Column('adj_reserve', sa.Numeric()), sa.Column('adj_comment', sa.String()), sa.Column('target_change', sa.Numeric()), sa.Column('base_plan_correction', sa.Numeric()), sa.Column('base_plan_correction_comment', sa.String()), sa.Column('payment_date', sa.Date()), sa.Column('payment_amount', sa.Numeric()), sa.Column('payment_amount_ho', sa.Numeric()), sa.Column('payment_amount_rf', sa.Numeric()), sa.Column('payment_comment', sa.String()), sa.Column('payment_act', sa.String()), sa.Column('actual_m1', sa.Numeric()), sa.Column('actual_m2', sa.Numeric()), sa.Column('actual_m3', sa.Numeric()), sa.Column('actual_spod', sa.Numeric()), sa.Column('transfer_to_q2', sa.Numeric()), sa.Column('transfer_to_q3', sa.Numeric()), sa.Column('transfer_to_q4', sa.Numeric()), sa.Column('transfer_to_economy', sa.Numeric()), sa.Column('transfer_delay_acts', sa.Numeric()), sa.Column('transfer_delay_procurement', sa.Numeric()), sa.Column('transfer_economy_rf', sa.Numeric()), sa.Column('transfer_next_comment', sa.String()), sa.Column('transfer_far_comment', sa.String()), sa.Column('booking_amount', sa.Numeric()), sa.Column('plan_revision_eco_change', sa.Numeric()), sa.Column('plan_revision_item_adj', sa.Numeric()), sa.Column('plan_revision_increase', sa.Numeric()), sa.Column('plan_revision_sequester', sa.Numeric()), sa.Column('plan_revision_comment', sa.String()), schema='v3', ) create_check_constraint_if_not_exists( 'chk_budget_line_quarter_quarter', 'budget_line_quarter', sa.text('quarter >= 1 AND quarter <= 4'), schema='v3', ) create_table_if_not_exists( 'ckk', sa.Column('line_id', sa.Integer(), primary_key=True), sa.Column('ceiling_amount', sa.Numeric()), sa.Column('expenses_q1', sa.Numeric()), sa.Column('expenses_q2', sa.Numeric()), sa.Column('expenses_q3', sa.Numeric()), sa.Column('expenses_q4', sa.Numeric()), sa.Column('expenses_next_year_q1', sa.Numeric()), sa.Column('expenses_next_year_q2', sa.Numeric()), sa.Column('expenses_next_year_q3', sa.Numeric()), sa.Column('expenses_next_year_q4', sa.Numeric()), sa.Column('rf_schedule', sa.String()), sa.Column('delivery_deadline', sa.String()), sa.Column('procurement_plan', sa.String()), sa.Column('procurement_method', sa.String()), sa.Column('comment', sa.String()), schema='v3', ) create_table_if_not_exists( 'collegial_approval', sa.Column('line_id', sa.Integer(), primary_key=True), sa.Column('approved_amount', sa.Numeric()), sa.Column('protocol_reference', sa.String()), sa.Column('note', sa.String()), schema='v3', ) create_table_if_not_exists( 'contract_detail', sa.Column('line_id', sa.Integer(), primary_key=True), sa.Column('counterparty', sa.String()), sa.Column('reference', sa.String()), sa.Column('addenda', sa.String()), sa.Column('subject', sa.String()), sa.Column('currency', sa.String()), sa.Column('ceiling_amount', sa.Numeric()), sa.Column('expenses_q1', sa.Numeric()), sa.Column('expenses_q2', sa.Numeric()), sa.Column('expenses_q3', sa.Numeric()), sa.Column('expenses_q4', sa.Numeric()), sa.Column('rf_schedule', sa.String()), sa.Column('vat_rate', sa.String()), sa.Column('exchange_rate', sa.Numeric()), sa.Column('amount_foreign', sa.Numeric()), sa.Column('deadline', sa.String()), sa.Column('payment_scheme', sa.String()), sa.Column('act', sa.String()), sa.Column('comment', sa.String()), sa.Column('contract_date', sa.Date()), schema='v3', ) create_table_if_not_exists( 'contract_summary', sa.Column('line_id', sa.Integer(), primary_key=True), sa.Column('total_amount', sa.Numeric()), sa.Column('counterparty', sa.String()), sa.Column('reference', sa.String()), sa.Column('deadline', sa.String()), sa.Column('comment', sa.String()), sa.Column('future_payments_y1', sa.Numeric()), sa.Column('future_payments_y2', sa.Numeric()), sa.Column('other_ssp_amount', sa.Numeric()), sa.Column('centralized_flag', sa.String()), schema='v3', ) create_table_if_not_exists( 'expense_item', sa.Column('id', sa.Integer(), primary_key=True), sa.Column('section_code', sa.String()), sa.Column('item_id', sa.String()), sa.Column('num_group_id', sa.String()), sa.Column('name', sa.String()), sa.Column('sheet', sa.String()), sa.Column('direction', sa.String()), sa.Column('parent_id', sa.Integer()), sa.Column('depth', sa.Integer()), schema='v3', ) create_check_constraint_if_not_exists( 'expense_item_sheet_check', 'expense_item', sa.text("sheet IN ('AHR', 'CAP', 'OPER')"), schema='v3', ) create_check_constraint_if_not_exists( 'expense_item_direction_check', 'expense_item', sa.text("direction IN ('Support', 'Development')"), schema='v3', ) create_index_if_not_exists( 'ix_v3_expense_item_parent', 'expense_item', ['parent_id'], schema='v3', ) create_index_if_not_exists( 'ix_v3_expense_item_sheet', 'expense_item', ['sheet'], schema='v3', ) create_table_if_not_exists( 'form_limit', sa.Column('budget_form_id', sa.Integer(), primary_key=True), sa.Column('template_id', sa.Integer(), primary_key=True), sa.Column('qty_q1', sa.Integer()), sa.Column('qty_q2', sa.Integer()), sa.Column('qty_q3', sa.Integer()), sa.Column('qty_q4', sa.Integer()), sa.Column('comment', sa.String()), schema='v3', ) create_index_if_not_exists( 'ix_v3_form_limit_form', 'form_limit', ['budget_form_id'], schema='v3', ) create_table_if_not_exists( 'form_phase', sa.Column('budget_form_id', sa.Integer(), primary_key=True), sa.Column('sheet', sa.String(), primary_key=True), sa.Column('phase_code', sa.String(), primary_key=True), sa.Column('role', sa.String(), nullable=False), sa.Column('column_keys', postgresql.ARRAY(sa.Text()), nullable=False), sa.Column('opens_at', sa.DateTime(timezone=True), nullable=False), sa.Column('closes_at', sa.DateTime(timezone=True), nullable=False), schema='v3', ) create_check_constraint_if_not_exists( 'chk_v4_form_phase_window', 'form_phase', sa.text('closes_at > opens_at'), schema='v3', ) create_check_constraint_if_not_exists( 'chk_v4_form_phase_columns', 'form_phase', sa.text('cardinality(column_keys) > 0'), schema='v3', ) create_check_constraint_if_not_exists( 'chk_v4_form_phase_no_admin', 'form_phase', sa.text("role != 'ADMIN'"), schema='v3', ) create_table_if_not_exists( 'form_type', sa.Column('code', sa.String(), primary_key=True), sa.Column('name', sa.String()), sa.Column('scope', sa.String()), sa.Column('storage_entity', sa.String()), schema='v3', ) create_check_constraint_if_not_exists( 'ck_form_type_scope', 'form_type', sa.text("scope IN ('GO','PD','RF')"), schema='v3', ) create_check_constraint_if_not_exists( 'ck_form_type_storage_entity', 'form_type', sa.text("storage_entity IN ('BUDGET_FORM','RF_PROJECT_REPORT')"), schema='v3', ) create_table_if_not_exists( 'limit_template', sa.Column('id', sa.Integer(), primary_key=True), sa.Column('parent_id', sa.Integer()), sa.Column('sort_order', sa.Integer(), nullable=False), sa.Column('row_type', sa.String(), nullable=False), sa.Column('section_no', sa.String()), sa.Column('expense_item_code', sa.String()), sa.Column('name', sa.String(), nullable=False), sa.Column('unit', sa.String()), sa.Column('limit_with_vat', sa.Numeric()), sa.Column('limit_without_vat', sa.Numeric()), schema='v3', ) create_check_constraint_if_not_exists( 'ck_v3_limit_template_row_type', 'limit_template', sa.text("row_type IN ('SECTION','GROUP','LEAF')"), schema='v3', ) create_index_if_not_exists( 'ix_v3_limit_template_parent', 'limit_template', ['parent_id'], schema='v3', ) create_table_if_not_exists( 'org_unit', sa.Column('id', sa.Integer(), primary_key=True), sa.Column('title', sa.String(), nullable=False), sa.Column('is_active', sa.Boolean(), nullable=False), sa.Column('is_ssp', sa.Boolean(), nullable=False), schema='v3', ) create_index_if_not_exists( 'ix_v4_org_unit_active', 'org_unit', ['is_active'], schema='v3', postgresql_where='is_active', ) create_table_if_not_exists( 'phase_template', sa.Column('form_type', sa.String(), primary_key=True), sa.Column('sheet', sa.String(), primary_key=True), sa.Column('phase_code', sa.String(), primary_key=True), sa.Column('role', sa.String(), nullable=False), sa.Column('column_keys', postgresql.ARRAY(sa.Text()), nullable=False), sa.Column('opens_at', sa.DateTime(timezone=True), nullable=False), sa.Column('closes_at', sa.DateTime(timezone=True), nullable=False), schema='v3', ) create_check_constraint_if_not_exists( 'chk_v4_phase_template_columns', 'phase_template', sa.text('cardinality(column_keys) > 0'), schema='v3', ) create_check_constraint_if_not_exists( 'chk_v4_phase_template_no_admin', 'phase_template', sa.text("role != 'ADMIN'"), schema='v3', ) create_check_constraint_if_not_exists( 'chk_v4_phase_template_window', 'phase_template', sa.text('closes_at > opens_at'), schema='v3', ) create_table_if_not_exists( 'plan', sa.Column('line_id', sa.Integer(), primary_key=True), sa.Column('plan_q1', sa.Numeric()), sa.Column('plan_q2', sa.Numeric()), sa.Column('plan_q3', sa.Numeric()), sa.Column('plan_q4', sa.Numeric()), sa.Column('comment', sa.String()), schema='v3', ) create_table_if_not_exists( 'project', sa.Column('id', sa.Integer(), primary_key=True), sa.Column('name', sa.String()), sa.Column('level', sa.String()), sa.Column('parent_id', sa.Integer()), sa.Column('project_type', sa.String()), sa.Column('vsp_format', sa.String()), sa.Column('placement_type', sa.String()), sa.Column('object_address', sa.String()), sa.Column('staff_count', sa.Integer()), sa.Column('total_area', sa.Numeric()), sa.Column('org_unit_id', sa.Integer()), schema='v3', ) create_check_constraint_if_not_exists( 'project_project_type_check', 'project', sa.text("project_type IS NULL OR project_type IN ('current', 'development')"), schema='v3', ) create_check_constraint_if_not_exists( 'project_level_check', 'project', sa.text("level IN ('program', 'project')"), schema='v3', ) create_check_constraint_if_not_exists( 'project_vsp_format_check', 'project', sa.text("vsp_format IS NULL OR vsp_format IN ('office', 'standalone', 'atm', 'other')"), schema='v3', ) create_check_constraint_if_not_exists( 'project_placement_type_check', 'project', sa.text("placement_type IS NULL OR placement_type IN ('own', 'rent', 'other')"), schema='v3', ) create_check_constraint_if_not_exists( 'chk_v3_project_name', 'project', sa.text("name IS NOT NULL AND name <> ''"), schema='v3', ) create_index_if_not_exists( 'ix_v3_project_ssp', 'project', ['org_unit_id'], schema='v3', ) create_table_if_not_exists( 'rent_detail', sa.Column('id', sa.Integer(), primary_key=True), sa.Column('line_id', sa.Integer(), nullable=False), sa.Column('vsp_id', sa.Integer(), nullable=False), sa.Column('contract_number', sa.String()), sa.Column('contract_end_date', sa.Date()), sa.Column('plan_q1', sa.Numeric()), sa.Column('plan_q2', sa.Numeric()), sa.Column('plan_q3', sa.Numeric()), sa.Column('plan_q4', sa.Numeric()), sa.Column('actual_jan', sa.Numeric()), sa.Column('actual_feb', sa.Numeric()), sa.Column('actual_mar', sa.Numeric()), sa.Column('actual_apr', sa.Numeric()), sa.Column('actual_may', sa.Numeric()), sa.Column('actual_jun', sa.Numeric()), sa.Column('actual_jul', sa.Numeric()), sa.Column('actual_aug', sa.Numeric()), sa.Column('actual_sep', sa.Numeric()), sa.Column('actual_oct', sa.Numeric()), sa.Column('actual_nov', sa.Numeric()), sa.Column('actual_dec', sa.Numeric()), sa.Column('comment', sa.String()), schema='v3', ) create_index_if_not_exists( 'ix_v3_rent_detail_line', 'rent_detail', ['line_id'], schema='v3', ) create_index_if_not_exists( 'ix_v3_rent_detail_vsp', 'rent_detail', ['vsp_id'], schema='v3', ) create_table_if_not_exists( 'reserve', sa.Column('line_id', sa.Integer(), primary_key=True), sa.Column('amount_q1', sa.Numeric()), sa.Column('amount_q2', sa.Numeric()), sa.Column('amount_q3', sa.Numeric()), sa.Column('amount_q4', sa.Numeric()), sa.Column('justification', sa.String()), schema='v3', ) create_table_if_not_exists( 'rf_project_report', sa.Column('id', sa.Integer(), primary_key=True), sa.Column('project_id', sa.Integer(), nullable=False), sa.Column('year', sa.Integer(), nullable=False), sa.Column('report_type', sa.String(), nullable=False), sa.Column('created_by', sa.Integer()), sa.Column('created_at', sa.DateTime(), server_default=sa.func.now()), sa.Column('updated_by', sa.Integer()), sa.Column('updated_at', sa.DateTime(), server_default=sa.func.now()), schema='v3', ) create_index_if_not_exists( 'ix_v3_rf_project_report_proj_year', 'rf_project_report', ['project_id', 'year'], schema='v3', ) create_unique_constraint_if_not_exists( 'uq_v3_rf_project_report', 'rf_project_report', ['project_id', 'year', 'report_type'], schema='v3', ) create_table_if_not_exists( 'rf_project_report_line', sa.Column('id', sa.Integer(), primary_key=True), sa.Column('rf_project_report_id', sa.Integer(), nullable=False), sa.Column('expense_item_id', sa.Integer(), nullable=False), schema='v3', ) create_index_if_not_exists( 'ix_v3_rf_project_report_line_rep', 'rf_project_report_line', ['rf_project_report_id'], schema='v3', ) create_unique_constraint_if_not_exists( 'uq_v3_rf_project_report_line', 'rf_project_report_line', ['rf_project_report_id', 'expense_item_id'], schema='v3', ) create_table_if_not_exists( 'rf_project_report_quarter', sa.Column('rf_project_report_line_id', sa.Integer(), primary_key=True), sa.Column('quarter', sa.SmallInteger(), primary_key=True), sa.Column('adj_by_items', sa.Numeric()), sa.Column('adj_increase', sa.Numeric()), sa.Column('actual_m1', sa.Numeric()), sa.Column('actual_m2', sa.Numeric()), sa.Column('actual_m3', sa.Numeric()), sa.Column('actual_spod', sa.Numeric()), schema='v3', ) create_table_if_not_exists( 'role', sa.Column('id', sa.Integer(), primary_key=True, autoincrement=False), sa.Column('code', sa.String(), nullable=False), schema='v3', ) create_unique_constraint_if_not_exists( 'uq_role_code', 'role', ['code'], schema='v3', ) create_table_if_not_exists( 'form3_phase', sa.Column('rf_project_report_id', sa.Integer(),primary_key=True), sa.Column('phase_code', sa.String(), primary_key=True), sa.Column('role', sa.String(), nullable=False), sa.Column('column_keys', postgresql.ARRAY(sa.Text()), nullable=False), sa.Column('opens_at', sa.DateTime(timezone=True), nullable=False), sa.Column('closes_at', sa.DateTime(timezone=True), nullable=False), schema='v3', ) create_check_constraint_if_not_exists( 'chk_v3_form3_phase_window', 'form3_phase', sa.text('closes_at > opens_at'), schema='v3', ) create_check_constraint_if_not_exists( 'chk_v3_form3_phase_columns', 'form3_phase', sa.text('cardinality(column_keys) > 0'), schema='v3', ) create_check_constraint_if_not_exists( 'chk_v3_form3_phase_no_admin', 'form3_phase', sa.text("role != 'ADMIN'"), schema='v3', ) create_index_if_not_exists( 'ix_v3_form3_phase_active', 'form3_phase', ['rf_project_report_id', 'role', 'opens_at', 'closes_at'], schema='v3', ) create_index_if_not_exists( 'ix_v3_form3_phase_columns_gin', 'form3_phase', ['column_keys'], schema='v3', postgresql_using='gin', ) create_table_if_not_exists( 'security_detail', sa.Column('id', sa.Integer(), primary_key=True), sa.Column('line_id', sa.Integer(), nullable=False), sa.Column('vsp_id', sa.Integer(), nullable=False), sa.Column('contract_number', sa.String()), sa.Column('contract_end_date', sa.Date()), sa.Column('plan_q1', sa.Numeric()), sa.Column('plan_q2', sa.Numeric()), sa.Column('plan_q3', sa.Numeric()), sa.Column('plan_q4', sa.Numeric()), sa.Column('actual_jan', sa.Numeric()), sa.Column('actual_feb', sa.Numeric()), sa.Column('actual_mar', sa.Numeric()), sa.Column('actual_apr', sa.Numeric()), sa.Column('actual_may', sa.Numeric()), sa.Column('actual_jun', sa.Numeric()), sa.Column('actual_jul', sa.Numeric()), sa.Column('actual_aug', sa.Numeric()), sa.Column('actual_sep', sa.Numeric()), sa.Column('actual_oct', sa.Numeric()), sa.Column('actual_nov', sa.Numeric()), sa.Column('actual_dec', sa.Numeric()), sa.Column('comment', sa.String()), schema='v3', ) create_index_if_not_exists( 'ix_v3_security_detail_vsp', 'security_detail', ['vsp_id'], schema='v3', ) create_index_if_not_exists( 'ix_v3_security_detail_line', 'security_detail', ['line_id'], schema='v3', ) create_table_if_not_exists( 'sequestration', sa.Column('id', sa.Integer(), primary_key=True), sa.Column('line_id', sa.Integer(), nullable=False), sa.Column('actor', sa.String(), nullable=False), sa.Column('adj_q1', sa.Numeric()), sa.Column('adj_q2', sa.Numeric()), sa.Column('adj_q3', sa.Numeric()), sa.Column('adj_q4', sa.Numeric()), sa.Column('justification', sa.String()), schema='v3', ) create_check_constraint_if_not_exists( 'ck_v3_sequestration_actor', 'sequestration', sa.text("actor IN ('DFIP','SSP_GO')"), schema='v3', ) create_index_if_not_exists( 'ix_v3_sequestration_line_actor', 'sequestration', ['line_id', 'actor'], schema='v3', ) create_unique_constraint_if_not_exists( 'uq_v3_sequestration_line_actor', 'sequestration', ['line_id', 'actor'], schema='v3', ) create_table_if_not_exists( 'user_org', sa.Column('id', sa.Integer(), primary_key=True), sa.Column('user_id', sa.Integer(), nullable=False), sa.Column('org_unit_id', sa.Integer(), nullable=False), schema='v3', ) create_index_if_not_exists( 'ix_v4_user_org_user', 'user_org', ['user_id'], schema='v3', ) create_index_if_not_exists( 'ix_v4_user_org_org', 'user_org', ['org_unit_id'], schema='v3', ) create_unique_constraint_if_not_exists( None, 'user_org', ['user_id', 'org_unit_id'], schema='v3', ) create_table_if_not_exists( 'utility_detail', sa.Column('id', sa.Integer(), primary_key=True), sa.Column('line_id', sa.Integer(), nullable=False), sa.Column('vsp_id', sa.Integer(), nullable=False), sa.Column('contract_number', sa.String()), sa.Column('contract_end_date', sa.Date()), sa.Column('plan_q1', sa.Numeric()), sa.Column('plan_q2', sa.Numeric()), sa.Column('plan_q3', sa.Numeric()), sa.Column('plan_q4', sa.Numeric()), sa.Column('actual_jan', sa.Numeric()), sa.Column('actual_feb', sa.Numeric()), sa.Column('actual_mar', sa.Numeric()), sa.Column('actual_apr', sa.Numeric()), sa.Column('actual_may', sa.Numeric()), sa.Column('actual_jun', sa.Numeric()), sa.Column('actual_jul', sa.Numeric()), sa.Column('actual_aug', sa.Numeric()), sa.Column('actual_sep', sa.Numeric()), sa.Column('actual_oct', sa.Numeric()), sa.Column('actual_nov', sa.Numeric()), sa.Column('actual_dec', sa.Numeric()), sa.Column('comment', sa.String()), schema='v3', ) create_index_if_not_exists( 'ix_v3_utility_detail_line', 'utility_detail', ['line_id'], schema='v3', ) create_index_if_not_exists( 'ix_v3_utility_detail_vsp', 'utility_detail', ['vsp_id'], schema='v3', ) create_table_if_not_exists( 'vsp', sa.Column('id', sa.Integer(), primary_key=True), sa.Column('branch_id', sa.Integer(), nullable=False), sa.Column('reg_number', sa.String()), sa.Column('address', sa.String()), sa.Column('format', sa.String()), sa.Column('opened_at', sa.Date()), sa.Column('placement_type', sa.String()), sa.Column('staff_count', sa.Integer()), sa.Column('total_area', sa.Numeric()), sa.Column('closed_at', sa.Date()), sa.Column('is_active', sa.Boolean(), nullable=False), sa.Column('is_deleted', sa.Boolean(), nullable=False), sa.Column('system_code', sa.String(100)), sa.Column('created_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), sa.Column('updated_at', sa.DateTime(timezone=True)), sa.Column('created_by', sa.Integer()), sa.Column('updated_by', sa.Integer()), sa.Column('vsp_type', sa.String(100)), sa.Column('notes', sa.Text()), sa.Column('location_form', sa.String()), sa.Column('rent_contract_num', sa.String()), sa.Column('rent_end_date', sa.Date()), schema='v3', ) create_check_constraint_if_not_exists( 'chk_closed_after_opened', 'vsp', sa.text('closed_at IS NULL OR opened_at IS NULL OR closed_at >= opened_at'), schema='v3', ) create_unique_constraint_if_not_exists( 'vsp_reg_number_unique', 'vsp', ['reg_number'], schema='v3', ) create_table_if_not_exists( 'fixed_asset_report', sa.Column('id', sa.Integer(), primary_key=True, autoincrement=True), sa.Column('budget_form_id', sa.Integer(), nullable=False), sa.Column('expense_item_id', sa.Integer()), sa.Column('equipment_name', sa.String()), sa.Column('month', sa.SmallInteger(), nullable=False), sa.Column('opening_qty_604', sa.Integer()), sa.Column('opening_amt_604', sa.Numeric()), sa.Column('acquired_qty_604', sa.Integer()), sa.Column('acquired_amt_604', sa.Numeric()), sa.Column('disposed_qty_604', sa.Integer()), sa.Column('disposed_amt_604', sa.Numeric()), sa.Column('opening_qty_60415', sa.Integer()), sa.Column('opening_amt_60415', sa.Numeric()), sa.Column('acquired_qty_60415', sa.Integer()), sa.Column('acquired_amt_60415', sa.Numeric()), sa.Column('transferred_qty_60415', sa.Integer()), sa.Column('transferred_amt_60415', sa.Numeric()), sa.Column('go_balance_only_amt', sa.Numeric()), schema='v3', ) create_check_constraint_if_not_exists( 'fixed_asset_report_month_check', 'fixed_asset_report', sa.text('month >= 1 AND month <= 12'), schema='v3', ) create_index_if_not_exists( 'ix_v3_fixed_asset_report_form', 'fixed_asset_report', ['budget_form_id'], schema='v3', ) create_index_if_not_exists( 'ix_v3_fixed_asset_report_item', 'fixed_asset_report', ['expense_item_id'], schema='v3', ) create_table_if_not_exists( 'expense_item_form_type', sa.Column('expense_item_id', sa.Integer(), primary_key=True), sa.Column('form_type_code', sa.String(), primary_key=True), schema='v3', ) create_index_if_not_exists( 'ix_v3_eift_item', 'expense_item_form_type', ['expense_item_id'], schema='v3', ) op.execute( """ CREATE MATERIALIZED VIEW IF NOT EXISTS v3.mv_expense_item_tree TABLESPACE pg_default AS WITH RECURSIVE tree AS ( SELECT ei.id, ei.sheet, ei.section_code, ei.item_id, ei.num_group_id, ei.name, ei.parent_id, ei.depth, ARRAY[ei.id] AS path, NULL::character varying AS parent_item_id FROM v3.expense_item ei WHERE ei.parent_id IS NULL UNION ALL SELECT ei.id, ei.sheet, ei.section_code, ei.item_id, ei.num_group_id, ei.name, ei.parent_id, ei.depth, t_1.path || ei.id, t_1.item_id AS parent_item_id FROM v3.expense_item ei JOIN tree t_1 ON ei.parent_id = t_1.id ) SELECT id, sheet, section_code, item_id, num_group_id, name, parent_id, parent_item_id, depth, path, ARRAY( SELECT c.id FROM tree c WHERE t.id = ANY (c.path)) AS desc_ids FROM tree t WITH DATA; """ ) op.execute("CREATE INDEX IF NOT EXISTS ix_v3_mv_expense_item_tree_sheet ON v3.mv_expense_item_tree USING btree (sheet);") op.execute("CREATE UNIQUE INDEX IF NOT EXISTS ux_v2_mv_expense_item_tree_id ON v3.mv_expense_item_tree USING btree (id);") def downgrade() -> None: pass