updates
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
73
Backend/alembic/versions/add_guest_requests_table.py
Normal file
73
Backend/alembic/versions/add_guest_requests_table.py
Normal file
@@ -0,0 +1,73 @@
|
||||
"""add_guest_requests_table
|
||||
|
||||
Revision ID: guest_requests_001
|
||||
Revises: inventory_management_001
|
||||
Create Date: 2025-01-02 14:00:00.000000
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'guest_requests_001'
|
||||
down_revision = 'inventory_management_001'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# Create guest_requests table
|
||||
op.create_table(
|
||||
'guest_requests',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('booking_id', sa.Integer(), nullable=False),
|
||||
sa.Column('room_id', sa.Integer(), nullable=False),
|
||||
sa.Column('user_id', sa.Integer(), nullable=False),
|
||||
sa.Column('request_type', sa.Enum(
|
||||
'extra_towels', 'extra_pillows', 'room_cleaning', 'turndown_service',
|
||||
'amenities', 'maintenance', 'room_service', 'other',
|
||||
name='requesttype'
|
||||
), nullable=False),
|
||||
sa.Column('status', sa.Enum(
|
||||
'pending', 'in_progress', 'fulfilled', 'cancelled',
|
||||
name='requeststatus'
|
||||
), nullable=False, server_default='pending'),
|
||||
sa.Column('priority', sa.Enum(
|
||||
'low', 'normal', 'high', 'urgent',
|
||||
name='requestpriority'
|
||||
), nullable=False, server_default='normal'),
|
||||
sa.Column('title', sa.String(255), nullable=False),
|
||||
sa.Column('description', sa.Text(), nullable=True),
|
||||
sa.Column('assigned_to', sa.Integer(), nullable=True),
|
||||
sa.Column('fulfilled_by', sa.Integer(), nullable=True),
|
||||
sa.Column('requested_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('started_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('fulfilled_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('guest_notes', sa.Text(), nullable=True),
|
||||
sa.Column('staff_notes', sa.Text(), nullable=True),
|
||||
sa.Column('response_time_minutes', sa.Integer(), nullable=True),
|
||||
sa.Column('fulfillment_time_minutes', sa.Integer(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['booking_id'], ['bookings.id'], ),
|
||||
sa.ForeignKeyConstraint(['room_id'], ['rooms.id'], ),
|
||||
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
|
||||
sa.ForeignKeyConstraint(['assigned_to'], ['users.id'], ),
|
||||
sa.ForeignKeyConstraint(['fulfilled_by'], ['users.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_guest_requests_id'), 'guest_requests', ['id'], unique=False)
|
||||
op.create_index(op.f('ix_guest_requests_booking_id'), 'guest_requests', ['booking_id'], unique=False)
|
||||
op.create_index(op.f('ix_guest_requests_room_id'), 'guest_requests', ['room_id'], unique=False)
|
||||
op.create_index(op.f('ix_guest_requests_requested_at'), 'guest_requests', ['requested_at'], unique=False)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_index(op.f('ix_guest_requests_requested_at'), table_name='guest_requests')
|
||||
op.drop_index(op.f('ix_guest_requests_room_id'), table_name='guest_requests')
|
||||
op.drop_index(op.f('ix_guest_requests_booking_id'), table_name='guest_requests')
|
||||
op.drop_index(op.f('ix_guest_requests_id'), table_name='guest_requests')
|
||||
op.drop_table('guest_requests')
|
||||
|
||||
171
Backend/alembic/versions/add_inventory_management_tables.py
Normal file
171
Backend/alembic/versions/add_inventory_management_tables.py
Normal file
@@ -0,0 +1,171 @@
|
||||
"""add_inventory_management_tables
|
||||
|
||||
Revision ID: inventory_management_001
|
||||
Revises: add_photos_to_housekeeping_tasks
|
||||
Create Date: 2025-01-02 12:00:00.000000
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'inventory_management_001'
|
||||
down_revision = 'add_photos_housekeeping'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# Create inventory_items table
|
||||
op.create_table(
|
||||
'inventory_items',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('name', sa.String(255), nullable=False),
|
||||
sa.Column('description', sa.Text(), nullable=True),
|
||||
sa.Column('category', sa.Enum(
|
||||
'cleaning_supplies', 'linens', 'toiletries', 'amenities',
|
||||
'maintenance', 'food_beverage', 'other',
|
||||
name='inventorycategory'
|
||||
), nullable=False),
|
||||
sa.Column('unit', sa.Enum(
|
||||
'piece', 'box', 'bottle', 'roll', 'pack', 'liter',
|
||||
'kilogram', 'meter', 'other',
|
||||
name='inventoryunit'
|
||||
), nullable=False),
|
||||
sa.Column('current_quantity', sa.Numeric(precision=10, scale=2), nullable=False, server_default='0'),
|
||||
sa.Column('minimum_quantity', sa.Numeric(precision=10, scale=2), nullable=False, server_default='0'),
|
||||
sa.Column('maximum_quantity', sa.Numeric(precision=10, scale=2), nullable=True),
|
||||
sa.Column('reorder_quantity', sa.Numeric(precision=10, scale=2), nullable=True),
|
||||
sa.Column('unit_cost', sa.Numeric(precision=10, scale=2), nullable=True),
|
||||
sa.Column('supplier', sa.String(255), nullable=True),
|
||||
sa.Column('supplier_contact', sa.Text(), nullable=True),
|
||||
sa.Column('storage_location', sa.String(255), nullable=True),
|
||||
sa.Column('is_active', sa.Boolean(), nullable=False, server_default='1'),
|
||||
sa.Column('is_tracked', sa.Boolean(), nullable=False, server_default='1'),
|
||||
sa.Column('barcode', sa.String(100), nullable=True),
|
||||
sa.Column('sku', sa.String(100), nullable=True),
|
||||
sa.Column('notes', sa.Text(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('created_by', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['created_by'], ['users.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_inventory_items_id'), 'inventory_items', ['id'], unique=False)
|
||||
op.create_index(op.f('ix_inventory_items_name'), 'inventory_items', ['name'], unique=False)
|
||||
op.create_index(op.f('ix_inventory_items_barcode'), 'inventory_items', ['barcode'], unique=True)
|
||||
op.create_index(op.f('ix_inventory_items_sku'), 'inventory_items', ['sku'], unique=True)
|
||||
|
||||
# Create inventory_transactions table
|
||||
op.create_table(
|
||||
'inventory_transactions',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('item_id', sa.Integer(), nullable=False),
|
||||
sa.Column('transaction_type', sa.Enum(
|
||||
'consumption', 'adjustment', 'received', 'transfer',
|
||||
'damaged', 'returned',
|
||||
name='transactiontype'
|
||||
), nullable=False),
|
||||
sa.Column('quantity', sa.Numeric(precision=10, scale=2), nullable=False),
|
||||
sa.Column('quantity_before', sa.Numeric(precision=10, scale=2), nullable=False),
|
||||
sa.Column('quantity_after', sa.Numeric(precision=10, scale=2), nullable=False),
|
||||
sa.Column('reference_type', sa.String(50), nullable=True),
|
||||
sa.Column('reference_id', sa.Integer(), nullable=True),
|
||||
sa.Column('notes', sa.Text(), nullable=True),
|
||||
sa.Column('cost', sa.Numeric(precision=10, scale=2), nullable=True),
|
||||
sa.Column('performed_by', sa.Integer(), nullable=True),
|
||||
sa.Column('transaction_date', sa.DateTime(), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['item_id'], ['inventory_items.id'], ),
|
||||
sa.ForeignKeyConstraint(['performed_by'], ['users.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_inventory_transactions_id'), 'inventory_transactions', ['id'], unique=False)
|
||||
op.create_index(op.f('ix_inventory_transactions_item_id'), 'inventory_transactions', ['item_id'], unique=False)
|
||||
op.create_index(op.f('ix_inventory_transactions_reference_id'), 'inventory_transactions', ['reference_id'], unique=False)
|
||||
op.create_index(op.f('ix_inventory_transactions_transaction_date'), 'inventory_transactions', ['transaction_date'], unique=False)
|
||||
|
||||
# Create inventory_reorder_requests table
|
||||
op.create_table(
|
||||
'inventory_reorder_requests',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('item_id', sa.Integer(), nullable=False),
|
||||
sa.Column('requested_quantity', sa.Numeric(precision=10, scale=2), nullable=False),
|
||||
sa.Column('current_quantity', sa.Numeric(precision=10, scale=2), nullable=False),
|
||||
sa.Column('minimum_quantity', sa.Numeric(precision=10, scale=2), nullable=False),
|
||||
sa.Column('status', sa.Enum(
|
||||
'pending', 'approved', 'ordered', 'received', 'cancelled',
|
||||
name='reorderstatus'
|
||||
), nullable=False, server_default='pending'),
|
||||
sa.Column('priority', sa.String(20), nullable=False, server_default='normal'),
|
||||
sa.Column('requested_by', sa.Integer(), nullable=False),
|
||||
sa.Column('requested_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('notes', sa.Text(), nullable=True),
|
||||
sa.Column('approved_by', sa.Integer(), nullable=True),
|
||||
sa.Column('approved_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('approval_notes', sa.Text(), nullable=True),
|
||||
sa.Column('order_number', sa.String(100), nullable=True),
|
||||
sa.Column('expected_delivery_date', sa.DateTime(), nullable=True),
|
||||
sa.Column('received_quantity', sa.Numeric(precision=10, scale=2), nullable=True),
|
||||
sa.Column('received_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['item_id'], ['inventory_items.id'], ),
|
||||
sa.ForeignKeyConstraint(['requested_by'], ['users.id'], ),
|
||||
sa.ForeignKeyConstraint(['approved_by'], ['users.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_inventory_reorder_requests_id'), 'inventory_reorder_requests', ['id'], unique=False)
|
||||
op.create_index(op.f('ix_inventory_reorder_requests_item_id'), 'inventory_reorder_requests', ['item_id'], unique=False)
|
||||
op.create_index(op.f('ix_inventory_reorder_requests_order_number'), 'inventory_reorder_requests', ['order_number'], unique=False)
|
||||
op.create_index(op.f('ix_inventory_reorder_requests_requested_at'), 'inventory_reorder_requests', ['requested_at'], unique=False)
|
||||
|
||||
# Create inventory_task_consumptions table
|
||||
op.create_table(
|
||||
'inventory_task_consumptions',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('task_id', sa.Integer(), nullable=False),
|
||||
sa.Column('item_id', sa.Integer(), nullable=False),
|
||||
sa.Column('quantity', sa.Numeric(precision=10, scale=2), nullable=False),
|
||||
sa.Column('notes', sa.Text(), nullable=True),
|
||||
sa.Column('recorded_by', sa.Integer(), nullable=True),
|
||||
sa.Column('recorded_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['task_id'], ['housekeeping_tasks.id'], ),
|
||||
sa.ForeignKeyConstraint(['item_id'], ['inventory_items.id'], ),
|
||||
sa.ForeignKeyConstraint(['recorded_by'], ['users.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_inventory_task_consumptions_id'), 'inventory_task_consumptions', ['id'], unique=False)
|
||||
op.create_index(op.f('ix_inventory_task_consumptions_task_id'), 'inventory_task_consumptions', ['task_id'], unique=False)
|
||||
op.create_index(op.f('ix_inventory_task_consumptions_item_id'), 'inventory_task_consumptions', ['item_id'], unique=False)
|
||||
op.create_index(op.f('ix_inventory_task_consumptions_recorded_at'), 'inventory_task_consumptions', ['recorded_at'], unique=False)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_index(op.f('ix_inventory_task_consumptions_recorded_at'), table_name='inventory_task_consumptions')
|
||||
op.drop_index(op.f('ix_inventory_task_consumptions_item_id'), table_name='inventory_task_consumptions')
|
||||
op.drop_index(op.f('ix_inventory_task_consumptions_task_id'), table_name='inventory_task_consumptions')
|
||||
op.drop_index(op.f('ix_inventory_task_consumptions_id'), table_name='inventory_task_consumptions')
|
||||
op.drop_table('inventory_task_consumptions')
|
||||
|
||||
op.drop_index(op.f('ix_inventory_reorder_requests_requested_at'), table_name='inventory_reorder_requests')
|
||||
op.drop_index(op.f('ix_inventory_reorder_requests_order_number'), table_name='inventory_reorder_requests')
|
||||
op.drop_index(op.f('ix_inventory_reorder_requests_item_id'), table_name='inventory_reorder_requests')
|
||||
op.drop_index(op.f('ix_inventory_reorder_requests_id'), table_name='inventory_reorder_requests')
|
||||
op.drop_table('inventory_reorder_requests')
|
||||
|
||||
op.drop_index(op.f('ix_inventory_transactions_transaction_date'), table_name='inventory_transactions')
|
||||
op.drop_index(op.f('ix_inventory_transactions_reference_id'), table_name='inventory_transactions')
|
||||
op.drop_index(op.f('ix_inventory_transactions_item_id'), table_name='inventory_transactions')
|
||||
op.drop_index(op.f('ix_inventory_transactions_id'), table_name='inventory_transactions')
|
||||
op.drop_table('inventory_transactions')
|
||||
|
||||
op.drop_index(op.f('ix_inventory_items_sku'), table_name='inventory_items')
|
||||
op.drop_index(op.f('ix_inventory_items_barcode'), table_name='inventory_items')
|
||||
op.drop_index(op.f('ix_inventory_items_name'), table_name='inventory_items')
|
||||
op.drop_index(op.f('ix_inventory_items_id'), table_name='inventory_items')
|
||||
op.drop_table('inventory_items')
|
||||
|
||||
28
Backend/alembic/versions/add_photos_to_housekeeping_tasks.py
Normal file
28
Backend/alembic/versions/add_photos_to_housekeeping_tasks.py
Normal file
@@ -0,0 +1,28 @@
|
||||
"""add_photos_to_housekeeping_tasks
|
||||
|
||||
Revision ID: add_photos_housekeeping
|
||||
Revises: d032f2351965
|
||||
Create Date: 2025-01-02 12:00:00.000000
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'add_photos_housekeeping'
|
||||
down_revision = 'd032f2351965'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# Add photos column to housekeeping_tasks table
|
||||
op.add_column('housekeeping_tasks', sa.Column('photos', sa.JSON(), nullable=True))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# Remove photos column
|
||||
op.drop_column('housekeeping_tasks', 'photos')
|
||||
|
||||
97
Backend/alembic/versions/add_staff_shifts_tables.py
Normal file
97
Backend/alembic/versions/add_staff_shifts_tables.py
Normal file
@@ -0,0 +1,97 @@
|
||||
"""add_staff_shifts_tables
|
||||
|
||||
Revision ID: staff_shifts_001
|
||||
Revises: guest_requests_001
|
||||
Create Date: 2025-01-02 16:00:00.000000
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'staff_shifts_001'
|
||||
down_revision = 'guest_requests_001'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# Create staff_shifts table
|
||||
op.create_table(
|
||||
'staff_shifts',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('staff_id', sa.Integer(), nullable=False),
|
||||
sa.Column('shift_date', sa.DateTime(), nullable=False),
|
||||
sa.Column('shift_type', sa.Enum('morning', 'afternoon', 'night', 'full_day', 'custom', name='shifttype'), nullable=False),
|
||||
sa.Column('start_time', sa.Time(), nullable=False),
|
||||
sa.Column('end_time', sa.Time(), nullable=False),
|
||||
sa.Column('status', sa.Enum('scheduled', 'in_progress', 'completed', 'cancelled', 'no_show', name='shiftstatus'), nullable=False, server_default='scheduled'),
|
||||
sa.Column('actual_start_time', sa.DateTime(), nullable=True),
|
||||
sa.Column('actual_end_time', sa.DateTime(), nullable=True),
|
||||
sa.Column('break_duration_minutes', sa.Integer(), nullable=True, server_default='30'),
|
||||
sa.Column('assigned_by', sa.Integer(), nullable=True),
|
||||
sa.Column('department', sa.String(length=100), nullable=True),
|
||||
sa.Column('notes', sa.Text(), nullable=True),
|
||||
sa.Column('handover_notes', sa.Text(), nullable=True),
|
||||
sa.Column('tasks_completed', sa.Integer(), nullable=True, server_default='0'),
|
||||
sa.Column('tasks_assigned', sa.Integer(), nullable=True, server_default='0'),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['assigned_by'], ['users.id'], ),
|
||||
sa.ForeignKeyConstraint(['staff_id'], ['users.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_staff_shifts_staff_id'), 'staff_shifts', ['staff_id'], unique=False)
|
||||
op.create_index(op.f('ix_staff_shifts_shift_date'), 'staff_shifts', ['shift_date'], unique=False)
|
||||
|
||||
# Create staff_tasks table
|
||||
op.create_table(
|
||||
'staff_tasks',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('shift_id', sa.Integer(), nullable=True),
|
||||
sa.Column('staff_id', sa.Integer(), nullable=False),
|
||||
sa.Column('title', sa.String(length=255), nullable=False),
|
||||
sa.Column('description', sa.Text(), nullable=True),
|
||||
sa.Column('task_type', sa.String(length=100), nullable=False),
|
||||
sa.Column('priority', sa.Enum('low', 'normal', 'high', 'urgent', name='stafftaskpriority'), nullable=False, server_default='normal'),
|
||||
sa.Column('status', sa.Enum('pending', 'assigned', 'in_progress', 'completed', 'cancelled', 'on_hold', name='stafftaskstatus'), nullable=False, server_default='pending'),
|
||||
sa.Column('scheduled_start', sa.DateTime(), nullable=True),
|
||||
sa.Column('scheduled_end', sa.DateTime(), nullable=True),
|
||||
sa.Column('actual_start', sa.DateTime(), nullable=True),
|
||||
sa.Column('actual_end', sa.DateTime(), nullable=True),
|
||||
sa.Column('estimated_duration_minutes', sa.Integer(), nullable=True),
|
||||
sa.Column('actual_duration_minutes', sa.Integer(), nullable=True),
|
||||
sa.Column('assigned_by', sa.Integer(), nullable=True),
|
||||
sa.Column('due_date', sa.DateTime(), nullable=True),
|
||||
sa.Column('related_booking_id', sa.Integer(), nullable=True),
|
||||
sa.Column('related_room_id', sa.Integer(), nullable=True),
|
||||
sa.Column('related_guest_request_id', sa.Integer(), nullable=True),
|
||||
sa.Column('related_maintenance_id', sa.Integer(), nullable=True),
|
||||
sa.Column('notes', sa.Text(), nullable=True),
|
||||
sa.Column('completion_notes', sa.Text(), nullable=True),
|
||||
sa.Column('is_recurring', sa.Boolean(), nullable=False, server_default='0'),
|
||||
sa.Column('recurrence_pattern', sa.String(length=100), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['assigned_by'], ['users.id'], ),
|
||||
sa.ForeignKeyConstraint(['related_booking_id'], ['bookings.id'], ),
|
||||
sa.ForeignKeyConstraint(['related_guest_request_id'], ['guest_requests.id'], ),
|
||||
sa.ForeignKeyConstraint(['related_maintenance_id'], ['room_maintenance.id'], ),
|
||||
sa.ForeignKeyConstraint(['related_room_id'], ['rooms.id'], ),
|
||||
sa.ForeignKeyConstraint(['shift_id'], ['staff_shifts.id'], ),
|
||||
sa.ForeignKeyConstraint(['staff_id'], ['users.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_staff_tasks_shift_id'), 'staff_tasks', ['shift_id'], unique=False)
|
||||
op.create_index(op.f('ix_staff_tasks_staff_id'), 'staff_tasks', ['staff_id'], unique=False)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_index(op.f('ix_staff_tasks_staff_id'), table_name='staff_tasks')
|
||||
op.drop_index(op.f('ix_staff_tasks_shift_id'), table_name='staff_tasks')
|
||||
op.drop_table('staff_tasks')
|
||||
op.drop_index(op.f('ix_staff_shifts_shift_date'), table_name='staff_shifts')
|
||||
op.drop_index(op.f('ix_staff_shifts_staff_id'), table_name='staff_shifts')
|
||||
op.drop_table('staff_shifts')
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
"""add_financial_audit_trail_table
|
||||
|
||||
Revision ID: d032f2351965
|
||||
Revises: 6f7f8689fc98
|
||||
Create Date: 2025-12-03 23:00:00.000000
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'd032f2351965'
|
||||
down_revision = '6f7f8689fc98'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# Check if table already exists
|
||||
from sqlalchemy import inspect
|
||||
bind = op.get_bind()
|
||||
inspector = inspect(bind)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
if 'financial_audit_trail' not in tables:
|
||||
# Create financial_audit_trail table
|
||||
op.create_table(
|
||||
'financial_audit_trail',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
|
||||
# Action details
|
||||
sa.Column('action_type', sa.Enum(
|
||||
'payment_created', 'payment_completed', 'payment_refunded',
|
||||
'payment_failed', 'invoice_created', 'invoice_updated',
|
||||
'invoice_paid', 'refund_processed', 'price_modified',
|
||||
'discount_applied', 'promotion_applied',
|
||||
name='financialactiontype'
|
||||
), nullable=False),
|
||||
sa.Column('action_description', sa.Text(), nullable=False),
|
||||
|
||||
# Related entities
|
||||
sa.Column('payment_id', sa.Integer(), nullable=True),
|
||||
sa.Column('invoice_id', sa.Integer(), nullable=True),
|
||||
sa.Column('booking_id', sa.Integer(), nullable=True),
|
||||
|
||||
# Financial details
|
||||
sa.Column('amount', sa.Numeric(precision=10, scale=2), nullable=True),
|
||||
sa.Column('previous_amount', sa.Numeric(precision=10, scale=2), nullable=True),
|
||||
sa.Column('currency', sa.String(length=3), nullable=True, server_default='USD'),
|
||||
|
||||
# User information
|
||||
sa.Column('performed_by', sa.Integer(), nullable=False),
|
||||
sa.Column('performed_by_email', sa.String(length=255), nullable=True),
|
||||
|
||||
# Additional context
|
||||
sa.Column('audit_metadata', sa.JSON(), nullable=True),
|
||||
sa.Column('notes', sa.Text(), nullable=True),
|
||||
|
||||
# Timestamp
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
|
||||
# Primary key
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
|
||||
# Foreign keys
|
||||
sa.ForeignKeyConstraint(['payment_id'], ['payments.id'], name='fk_financial_audit_payment'),
|
||||
sa.ForeignKeyConstraint(['invoice_id'], ['invoices.id'], name='fk_financial_audit_invoice'),
|
||||
sa.ForeignKeyConstraint(['booking_id'], ['bookings.id'], name='fk_financial_audit_booking'),
|
||||
sa.ForeignKeyConstraint(['performed_by'], ['users.id'], name='fk_financial_audit_user')
|
||||
)
|
||||
|
||||
# Create indexes
|
||||
op.create_index(op.f('ix_financial_audit_trail_id'), 'financial_audit_trail', ['id'], unique=False)
|
||||
op.create_index(op.f('ix_financial_audit_trail_action_type'), 'financial_audit_trail', ['action_type'], unique=False)
|
||||
op.create_index(op.f('ix_financial_audit_trail_payment_id'), 'financial_audit_trail', ['payment_id'], unique=False)
|
||||
op.create_index(op.f('ix_financial_audit_trail_invoice_id'), 'financial_audit_trail', ['invoice_id'], unique=False)
|
||||
op.create_index(op.f('ix_financial_audit_trail_booking_id'), 'financial_audit_trail', ['booking_id'], unique=False)
|
||||
op.create_index(op.f('ix_financial_audit_trail_performed_by'), 'financial_audit_trail', ['performed_by'], unique=False)
|
||||
op.create_index(op.f('ix_financial_audit_trail_created_at'), 'financial_audit_trail', ['created_at'], unique=False)
|
||||
|
||||
# Create composite indexes
|
||||
op.create_index('idx_financial_audit_created', 'financial_audit_trail', ['created_at'], unique=False)
|
||||
op.create_index('idx_financial_audit_action', 'financial_audit_trail', ['action_type', 'created_at'], unique=False)
|
||||
op.create_index('idx_financial_audit_user', 'financial_audit_trail', ['performed_by', 'created_at'], unique=False)
|
||||
op.create_index('idx_financial_audit_booking', 'financial_audit_trail', ['booking_id', 'created_at'], unique=False)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# Drop indexes first
|
||||
op.drop_index('idx_financial_audit_booking', table_name='financial_audit_trail')
|
||||
op.drop_index('idx_financial_audit_user', table_name='financial_audit_trail')
|
||||
op.drop_index('idx_financial_audit_action', table_name='financial_audit_trail')
|
||||
op.drop_index('idx_financial_audit_created', table_name='financial_audit_trail')
|
||||
|
||||
op.drop_index(op.f('ix_financial_audit_trail_created_at'), table_name='financial_audit_trail')
|
||||
op.drop_index(op.f('ix_financial_audit_trail_performed_by'), table_name='financial_audit_trail')
|
||||
op.drop_index(op.f('ix_financial_audit_trail_booking_id'), table_name='financial_audit_trail')
|
||||
op.drop_index(op.f('ix_financial_audit_trail_invoice_id'), table_name='financial_audit_trail')
|
||||
op.drop_index(op.f('ix_financial_audit_trail_payment_id'), table_name='financial_audit_trail')
|
||||
op.drop_index(op.f('ix_financial_audit_trail_action_type'), table_name='financial_audit_trail')
|
||||
op.drop_index(op.f('ix_financial_audit_trail_id'), table_name='financial_audit_trail')
|
||||
|
||||
# Drop table
|
||||
op.drop_table('financial_audit_trail')
|
||||
Reference in New Issue
Block a user