refactor: Unify database migrations into single initial schemas
Consolidated incremental migrations into single unified initial schema files for both procurement and production services. This simplifies database setup and eliminates migration chain complexity. Changes: - Procurement: Merged 3 migrations into 001_unified_initial_schema.py - Initial schema (20251015_1229) - Add supplier_price_list_id (20251030_0737) - Add JTBD reasoning fields (20251107) - Production: Merged 3 migrations into 001_unified_initial_schema.py - Initial schema (20251015_1231) - Add waste tracking fields (20251023_0900) - Add JTBD reasoning fields (20251107) All new fields (reasoning, consequence, reasoning_data, waste_defect_type, is_ai_assisted, supplier_price_list_id) are now included in the initial schemas from the start. Updated model files to use deferred() for reasoning fields to prevent breaking queries when running against existing databases.
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
"""initial procurement schema
|
||||
"""unified initial procurement schema
|
||||
|
||||
Revision ID: 20251015_1229
|
||||
Revision ID: 001_unified_initial_schema
|
||||
Revises:
|
||||
Create Date: 2025-10-15 12:29:00.00000+02:00
|
||||
Create Date: 2025-11-07
|
||||
|
||||
Complete procurement service schema including:
|
||||
- Procurement plans and requirements
|
||||
- Purchase orders and items
|
||||
- Purchase orders and items (with reasoning fields for JTBD dashboard)
|
||||
- Deliveries and delivery items
|
||||
- Supplier invoices
|
||||
- Replenishment planning
|
||||
@@ -21,7 +21,7 @@ import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '20251015_1229'
|
||||
revision: str = '001_unified_initial_schema'
|
||||
down_revision: Union[str, None] = None
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
@@ -31,7 +31,7 @@ def upgrade() -> None:
|
||||
# Create PostgreSQL enum types first
|
||||
# PurchaseOrderStatus enum
|
||||
purchaseorderstatus_enum = postgresql.ENUM(
|
||||
'draft', 'pending_approval', 'approved', 'sent_to_supplier',
|
||||
'draft', 'pending_approval', 'approved', 'sent_to_supplier',
|
||||
'confirmed', 'partially_received', 'completed', 'cancelled', 'disputed',
|
||||
name='purchaseorderstatus',
|
||||
create_type=False
|
||||
@@ -207,7 +207,7 @@ def upgrade() -> None:
|
||||
# PURCHASE ORDER TABLES
|
||||
# ========================================================================
|
||||
|
||||
# Create purchase_orders table
|
||||
# Create purchase_orders table (with JTBD dashboard reasoning fields)
|
||||
op.create_table('purchase_orders',
|
||||
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column('tenant_id', postgresql.UUID(as_uuid=True), nullable=False),
|
||||
@@ -242,6 +242,10 @@ def upgrade() -> None:
|
||||
sa.Column('notes', sa.Text(), nullable=True),
|
||||
sa.Column('internal_notes', sa.Text(), nullable=True),
|
||||
sa.Column('terms_and_conditions', sa.Text(), nullable=True),
|
||||
# JTBD Dashboard fields
|
||||
sa.Column('reasoning', sa.Text(), nullable=True),
|
||||
sa.Column('consequence', sa.Text(), nullable=True),
|
||||
sa.Column('reasoning_data', postgresql.JSONB(astext_type=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()'), onupdate=sa.text('now()'), nullable=False),
|
||||
sa.Column('created_by', postgresql.UUID(as_uuid=True), nullable=False),
|
||||
@@ -260,13 +264,14 @@ def upgrade() -> None:
|
||||
op.create_index('ix_purchase_orders_order_date', 'purchase_orders', ['order_date'], unique=False)
|
||||
op.create_index('ix_purchase_orders_delivery_date', 'purchase_orders', ['required_delivery_date'], unique=False)
|
||||
|
||||
# Create purchase_order_items table
|
||||
# Create purchase_order_items table (with supplier_price_list_id)
|
||||
op.create_table('purchase_order_items',
|
||||
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column('tenant_id', postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column('purchase_order_id', postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column('procurement_requirement_id', postgresql.UUID(as_uuid=True), nullable=True),
|
||||
sa.Column('inventory_product_id', postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column('supplier_price_list_id', postgresql.UUID(as_uuid=True), nullable=True),
|
||||
sa.Column('product_code', sa.String(length=100), nullable=True),
|
||||
sa.Column('product_name', sa.String(length=200), nullable=False),
|
||||
sa.Column('ordered_quantity', sa.Numeric(precision=12, scale=3), nullable=False),
|
||||
@@ -286,6 +291,7 @@ def upgrade() -> None:
|
||||
op.create_index(op.f('ix_purchase_order_items_inventory_product_id'), 'purchase_order_items', ['inventory_product_id'], unique=False)
|
||||
op.create_index(op.f('ix_purchase_order_items_procurement_requirement_id'), 'purchase_order_items', ['procurement_requirement_id'], unique=False)
|
||||
op.create_index(op.f('ix_purchase_order_items_purchase_order_id'), 'purchase_order_items', ['purchase_order_id'], unique=False)
|
||||
op.create_index(op.f('ix_purchase_order_items_supplier_price_list_id'), 'purchase_order_items', ['supplier_price_list_id'], unique=False)
|
||||
op.create_index(op.f('ix_purchase_order_items_tenant_id'), 'purchase_order_items', ['tenant_id'], unique=False)
|
||||
op.create_index('ix_po_items_tenant_po', 'purchase_order_items', ['tenant_id', 'purchase_order_id'], unique=False)
|
||||
op.create_index('ix_po_items_inventory_product', 'purchase_order_items', ['inventory_product_id'], unique=False)
|
||||
@@ -594,7 +600,7 @@ def downgrade() -> None:
|
||||
op.drop_table('purchase_orders')
|
||||
op.drop_table('procurement_requirements')
|
||||
op.drop_table('procurement_plans')
|
||||
|
||||
|
||||
# Drop enum types
|
||||
op.execute("DROP TYPE IF EXISTS purchaseorderstatus")
|
||||
op.execute("DROP TYPE IF EXISTS deliverystatus")
|
||||
@@ -1,42 +0,0 @@
|
||||
"""add_supplier_price_list_id_to_purchase_order_items
|
||||
|
||||
Revision ID: 9450f58f3623
|
||||
Revises: 20251015_1229
|
||||
Create Date: 2025-10-30 07:37:07.477603
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '9450f58f3623'
|
||||
down_revision: Union[str, None] = '20251015_1229'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# Add supplier_price_list_id column to purchase_order_items table
|
||||
op.add_column('purchase_order_items',
|
||||
sa.Column('supplier_price_list_id', postgresql.UUID(as_uuid=True), nullable=True)
|
||||
)
|
||||
|
||||
# Create index on supplier_price_list_id
|
||||
op.create_index(
|
||||
'ix_purchase_order_items_supplier_price_list_id',
|
||||
'purchase_order_items',
|
||||
['supplier_price_list_id'],
|
||||
unique=False
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# Drop index first
|
||||
op.drop_index('ix_purchase_order_items_supplier_price_list_id', table_name='purchase_order_items')
|
||||
|
||||
# Drop column
|
||||
op.drop_column('purchase_order_items', 'supplier_price_list_id')
|
||||
@@ -1,30 +0,0 @@
|
||||
"""add reasoning fields to purchase orders
|
||||
|
||||
Revision ID: 20251107_add_reasoning_fields
|
||||
Revises: 20251030_0737_9450f58f3623
|
||||
Create Date: 2025-11-07
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '20251107_add_reasoning_fields'
|
||||
down_revision = '20251030_0737_9450f58f3623'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# Add reasoning fields to purchase_orders table
|
||||
op.add_column('purchase_orders', sa.Column('reasoning', sa.Text(), nullable=True))
|
||||
op.add_column('purchase_orders', sa.Column('consequence', sa.Text(), nullable=True))
|
||||
op.add_column('purchase_orders', sa.Column('reasoning_data', postgresql.JSONB(astext_type=sa.Text()), nullable=True))
|
||||
|
||||
|
||||
def downgrade():
|
||||
# Remove reasoning fields from purchase_orders table
|
||||
op.drop_column('purchase_orders', 'reasoning_data')
|
||||
op.drop_column('purchase_orders', 'consequence')
|
||||
op.drop_column('purchase_orders', 'reasoning')
|
||||
Reference in New Issue
Block a user