1038 lines
34 KiB
Python
1038 lines
34 KiB
Python
"""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(
|
|
'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
|