""" Initial schema for Distribution Service Revision ID: 001 Revises: Create Date: 2024-12-01 13:00:00.000000 """ from alembic import op import sqlalchemy as sa from sqlalchemy.dialects import postgresql # revision identifiers, used by Alembic. revision = '001' down_revision = None branch_labels = None depends_on = None def upgrade(): # Create enum types op.execute("CREATE TYPE deliveryroutestatus AS ENUM ('planned', 'in_progress', 'completed', 'cancelled')") op.execute("CREATE TYPE shipmentstatus AS ENUM ('pending', 'packed', 'in_transit', 'delivered', 'failed')") op.execute("CREATE TYPE deliveryschedulefrequency AS ENUM ('daily', 'weekly', 'biweekly', 'monthly')") # Create delivery_routes table op.create_table('delivery_routes', sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('tenant_id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('route_number', sa.String(length=50), nullable=False), sa.Column('route_date', sa.DateTime(timezone=True), nullable=False), sa.Column('vehicle_id', sa.String(length=100), nullable=True), sa.Column('driver_id', postgresql.UUID(as_uuid=True), nullable=True), sa.Column('total_distance_km', sa.Float(), nullable=True), sa.Column('estimated_duration_minutes', sa.Integer(), nullable=True), sa.Column('route_sequence', postgresql.JSONB(astext_type=sa.Text()), nullable=True), sa.Column('notes', sa.Text(), nullable=True), sa.Column('status', postgresql.ENUM('planned', 'in_progress', 'completed', 'cancelled', name='deliveryroutestatus', create_type=False), nullable=False, server_default='planned'), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.Column('created_by', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('updated_by', postgresql.UUID(as_uuid=True), nullable=False), sa.PrimaryKeyConstraint('id'), sa.UniqueConstraint('route_number') ) # Create indexes for delivery_routes op.create_index('ix_delivery_routes_tenant_id', 'delivery_routes', ['tenant_id']) op.create_index('ix_delivery_routes_route_date', 'delivery_routes', ['route_date']) op.create_index('ix_delivery_routes_route_number', 'delivery_routes', ['route_number']) op.create_index('ix_delivery_routes_status', 'delivery_routes', ['status']) op.create_index('ix_delivery_routes_driver_id', 'delivery_routes', ['driver_id']) op.create_index('ix_delivery_routes_tenant_date', 'delivery_routes', ['tenant_id', 'route_date']) op.create_index('ix_delivery_routes_date_tenant_status', 'delivery_routes', ['route_date', 'tenant_id', 'status']) # Create shipments table op.create_table('shipments', sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('tenant_id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('parent_tenant_id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('child_tenant_id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('purchase_order_id', postgresql.UUID(as_uuid=True), nullable=True), sa.Column('delivery_route_id', postgresql.UUID(as_uuid=True), nullable=True), sa.Column('shipment_number', sa.String(length=50), nullable=False), sa.Column('shipment_date', sa.DateTime(timezone=True), nullable=False), sa.Column('current_location_lat', sa.Float(), nullable=True), sa.Column('current_location_lng', sa.Float(), nullable=True), sa.Column('last_tracked_at', sa.DateTime(timezone=True), nullable=True), sa.Column('status', postgresql.ENUM('pending', 'packed', 'in_transit', 'delivered', 'failed', name='shipmentstatus', create_type=False), nullable=False, server_default='pending'), sa.Column('actual_delivery_time', sa.DateTime(timezone=True), nullable=True), sa.Column('signature', sa.Text(), nullable=True), sa.Column('photo_url', sa.String(length=500), nullable=True), sa.Column('received_by_name', sa.String(length=200), nullable=True), sa.Column('delivery_notes', sa.Text(), nullable=True), sa.Column('total_weight_kg', sa.Float(), nullable=True), sa.Column('total_volume_m3', sa.Float(), nullable=True), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.Column('created_by', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('updated_by', postgresql.UUID(as_uuid=True), nullable=False), sa.ForeignKeyConstraint(['delivery_route_id'], ['delivery_routes.id'], ondelete='SET NULL'), sa.PrimaryKeyConstraint('id'), sa.UniqueConstraint('shipment_number') ) # Create indexes for shipments op.create_index('ix_shipments_tenant_id', 'shipments', ['tenant_id']) op.create_index('ix_shipments_parent_tenant_id', 'shipments', ['parent_tenant_id']) op.create_index('ix_shipments_child_tenant_id', 'shipments', ['child_tenant_id']) op.create_index('ix_shipments_purchase_order_id', 'shipments', ['purchase_order_id']) op.create_index('ix_shipments_delivery_route_id', 'shipments', ['delivery_route_id']) op.create_index('ix_shipments_shipment_number', 'shipments', ['shipment_number']) op.create_index('ix_shipments_shipment_date', 'shipments', ['shipment_date']) op.create_index('ix_shipments_status', 'shipments', ['status']) op.create_index('ix_shipments_tenant_status', 'shipments', ['tenant_id', 'status']) op.create_index('ix_shipments_parent_child', 'shipments', ['parent_tenant_id', 'child_tenant_id']) op.create_index('ix_shipments_date_tenant', 'shipments', ['shipment_date', 'tenant_id']) # Create delivery_schedules table op.create_table('delivery_schedules', sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('tenant_id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('name', sa.String(length=200), nullable=False), sa.Column('delivery_days', sa.String(length=200), nullable=False), sa.Column('delivery_time', sa.String(length=20), nullable=False), sa.Column('frequency', postgresql.ENUM('daily', 'weekly', 'biweekly', 'monthly', name='deliveryschedulefrequency', create_type=False), nullable=False, server_default='weekly'), sa.Column('auto_generate_orders', sa.Boolean(), nullable=False, server_default='false'), sa.Column('lead_time_days', sa.Integer(), nullable=False, server_default='1'), sa.Column('target_parent_tenant_id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('target_child_tenant_ids', postgresql.JSONB(astext_type=sa.Text()), nullable=False), sa.Column('is_active', sa.Boolean(), nullable=False, server_default='true'), sa.Column('notes', sa.Text(), nullable=True), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.Column('created_by', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('updated_by', postgresql.UUID(as_uuid=True), nullable=False), sa.PrimaryKeyConstraint('id') ) # Create indexes for delivery_schedules op.create_index('ix_delivery_schedules_tenant_id', 'delivery_schedules', ['tenant_id']) op.create_index('ix_delivery_schedules_target_parent_tenant_id', 'delivery_schedules', ['target_parent_tenant_id']) op.create_index('ix_delivery_schedules_is_active', 'delivery_schedules', ['is_active']) op.create_index('ix_delivery_schedules_tenant_active', 'delivery_schedules', ['tenant_id', 'is_active']) op.create_index('ix_delivery_schedules_parent_tenant', 'delivery_schedules', ['target_parent_tenant_id']) def downgrade(): # Drop indexes for delivery_schedules op.drop_index('ix_delivery_schedules_parent_tenant', table_name='delivery_schedules') op.drop_index('ix_delivery_schedules_tenant_active', table_name='delivery_schedules') op.drop_index('ix_delivery_schedules_is_active', table_name='delivery_schedules') op.drop_index('ix_delivery_schedules_target_parent_tenant_id', table_name='delivery_schedules') op.drop_index('ix_delivery_schedules_tenant_id', table_name='delivery_schedules') # Drop delivery_schedules table op.drop_table('delivery_schedules') # Drop indexes for shipments op.drop_index('ix_shipments_date_tenant', table_name='shipments') op.drop_index('ix_shipments_parent_child', table_name='shipments') op.drop_index('ix_shipments_tenant_status', table_name='shipments') op.drop_index('ix_shipments_status', table_name='shipments') op.drop_index('ix_shipments_shipment_date', table_name='shipments') op.drop_index('ix_shipments_shipment_number', table_name='shipments') op.drop_index('ix_shipments_delivery_route_id', table_name='shipments') op.drop_index('ix_shipments_purchase_order_id', table_name='shipments') op.drop_index('ix_shipments_child_tenant_id', table_name='shipments') op.drop_index('ix_shipments_parent_tenant_id', table_name='shipments') op.drop_index('ix_shipments_tenant_id', table_name='shipments') # Drop shipments table op.drop_table('shipments') # Drop indexes for delivery_routes op.drop_index('ix_delivery_routes_date_tenant_status', table_name='delivery_routes') op.drop_index('ix_delivery_routes_tenant_date', table_name='delivery_routes') op.drop_index('ix_delivery_routes_driver_id', table_name='delivery_routes') op.drop_index('ix_delivery_routes_status', table_name='delivery_routes') op.drop_index('ix_delivery_routes_route_number', table_name='delivery_routes') op.drop_index('ix_delivery_routes_route_date', table_name='delivery_routes') op.drop_index('ix_delivery_routes_tenant_id', table_name='delivery_routes') # Drop delivery_routes table op.drop_table('delivery_routes') # Drop enum types op.execute("DROP TYPE IF EXISTS deliveryschedulefrequency") op.execute("DROP TYPE IF EXISTS shipmentstatus") op.execute("DROP TYPE IF EXISTS deliveryroutestatus")