Fix new services implementation 3

This commit is contained in:
Urtzi Alfaro
2025-08-14 16:47:34 +02:00
parent 0951547e92
commit 03737430ee
51 changed files with 657 additions and 982 deletions

View File

@@ -1,404 +0,0 @@
"""Initial supplier and procurement tables
Revision ID: 001_initial_supplier_tables
Revises:
Create Date: 2024-01-15 10:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import UUID, JSONB
# revision identifiers, used by Alembic.
revision = '001_initial_supplier_tables'
down_revision = None
branch_labels = None
depends_on = None
def upgrade() -> None:
# Create suppliers table
op.create_table('suppliers',
sa.Column('id', UUID(as_uuid=True), nullable=False, primary_key=True),
sa.Column('tenant_id', UUID(as_uuid=True), nullable=False),
sa.Column('name', sa.String(255), nullable=False),
sa.Column('supplier_code', sa.String(50), nullable=True),
sa.Column('tax_id', sa.String(50), nullable=True),
sa.Column('registration_number', sa.String(100), nullable=True),
sa.Column('supplier_type', sa.Enum('INGREDIENTS', 'PACKAGING', 'EQUIPMENT', 'SERVICES', 'UTILITIES', 'MULTI', name='suppliertype'), nullable=False),
sa.Column('status', sa.Enum('ACTIVE', 'INACTIVE', 'PENDING_APPROVAL', 'SUSPENDED', 'BLACKLISTED', name='supplierstatus'), nullable=False, default='PENDING_APPROVAL'),
sa.Column('contact_person', sa.String(200), nullable=True),
sa.Column('email', sa.String(254), nullable=True),
sa.Column('phone', sa.String(30), nullable=True),
sa.Column('mobile', sa.String(30), nullable=True),
sa.Column('website', sa.String(255), nullable=True),
sa.Column('address_line1', sa.String(255), nullable=True),
sa.Column('address_line2', sa.String(255), nullable=True),
sa.Column('city', sa.String(100), nullable=True),
sa.Column('state_province', sa.String(100), nullable=True),
sa.Column('postal_code', sa.String(20), nullable=True),
sa.Column('country', sa.String(100), nullable=True),
sa.Column('payment_terms', sa.Enum('CASH_ON_DELIVERY', 'NET_15', 'NET_30', 'NET_45', 'NET_60', 'PREPAID', 'CREDIT_TERMS', name='paymentterms'), nullable=False, default='NET_30'),
sa.Column('credit_limit', sa.Numeric(12, 2), nullable=True),
sa.Column('currency', sa.String(3), nullable=False, default='EUR'),
sa.Column('standard_lead_time', sa.Integer(), nullable=False, default=3),
sa.Column('minimum_order_amount', sa.Numeric(10, 2), nullable=True),
sa.Column('delivery_area', sa.String(255), nullable=True),
sa.Column('quality_rating', sa.Float(), nullable=True, default=0.0),
sa.Column('delivery_rating', sa.Float(), nullable=True, default=0.0),
sa.Column('total_orders', sa.Integer(), nullable=False, default=0),
sa.Column('total_amount', sa.Numeric(12, 2), nullable=False, default=0.0),
sa.Column('approved_by', UUID(as_uuid=True), nullable=True),
sa.Column('approved_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('rejection_reason', sa.Text(), nullable=True),
sa.Column('notes', sa.Text(), nullable=True),
sa.Column('certifications', JSONB, nullable=True),
sa.Column('business_hours', JSONB, nullable=True),
sa.Column('specializations', JSONB, nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('created_by', UUID(as_uuid=True), nullable=False),
sa.Column('updated_by', UUID(as_uuid=True), nullable=False)
)
# Create supplier_price_lists table
op.create_table('supplier_price_lists',
sa.Column('id', UUID(as_uuid=True), nullable=False, primary_key=True),
sa.Column('tenant_id', UUID(as_uuid=True), nullable=False),
sa.Column('supplier_id', UUID(as_uuid=True), nullable=False),
sa.Column('ingredient_id', UUID(as_uuid=True), nullable=False),
sa.Column('product_code', sa.String(100), nullable=True),
sa.Column('product_name', sa.String(255), nullable=False),
sa.Column('unit_price', sa.Numeric(10, 4), nullable=False),
sa.Column('unit_of_measure', sa.String(20), nullable=False),
sa.Column('minimum_order_quantity', sa.Integer(), nullable=True, default=1),
sa.Column('price_per_unit', sa.Numeric(10, 4), nullable=False),
sa.Column('tier_pricing', JSONB, nullable=True),
sa.Column('effective_date', sa.DateTime(timezone=True), nullable=False),
sa.Column('expiry_date', sa.DateTime(timezone=True), nullable=True),
sa.Column('is_active', sa.Boolean(), nullable=False, default=True),
sa.Column('brand', sa.String(100), nullable=True),
sa.Column('packaging_size', sa.String(50), nullable=True),
sa.Column('origin_country', sa.String(100), nullable=True),
sa.Column('shelf_life_days', sa.Integer(), nullable=True),
sa.Column('storage_requirements', sa.Text(), nullable=True),
sa.Column('quality_specs', JSONB, nullable=True),
sa.Column('allergens', JSONB, nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('created_by', UUID(as_uuid=True), nullable=False),
sa.Column('updated_by', UUID(as_uuid=True), nullable=False),
sa.ForeignKeyConstraint(['supplier_id'], ['suppliers.id'])
)
# Create purchase_orders table
op.create_table('purchase_orders',
sa.Column('id', UUID(as_uuid=True), nullable=False, primary_key=True),
sa.Column('tenant_id', UUID(as_uuid=True), nullable=False),
sa.Column('supplier_id', UUID(as_uuid=True), nullable=False),
sa.Column('po_number', sa.String(50), nullable=False),
sa.Column('reference_number', sa.String(100), nullable=True),
sa.Column('status', sa.Enum('DRAFT', 'PENDING_APPROVAL', 'APPROVED', 'SENT_TO_SUPPLIER', 'CONFIRMED', 'PARTIALLY_RECEIVED', 'COMPLETED', 'CANCELLED', 'DISPUTED', name='purchaseorderstatus'), nullable=False, default='DRAFT'),
sa.Column('priority', sa.String(20), nullable=False, default='normal'),
sa.Column('order_date', sa.DateTime(timezone=True), nullable=False),
sa.Column('required_delivery_date', sa.DateTime(timezone=True), nullable=True),
sa.Column('estimated_delivery_date', sa.DateTime(timezone=True), nullable=True),
sa.Column('subtotal', sa.Numeric(12, 2), nullable=False, default=0.0),
sa.Column('tax_amount', sa.Numeric(12, 2), nullable=False, default=0.0),
sa.Column('shipping_cost', sa.Numeric(10, 2), nullable=False, default=0.0),
sa.Column('discount_amount', sa.Numeric(10, 2), nullable=False, default=0.0),
sa.Column('total_amount', sa.Numeric(12, 2), nullable=False, default=0.0),
sa.Column('currency', sa.String(3), nullable=False, default='EUR'),
sa.Column('delivery_address', sa.Text(), nullable=True),
sa.Column('delivery_instructions', sa.Text(), nullable=True),
sa.Column('delivery_contact', sa.String(200), nullable=True),
sa.Column('delivery_phone', sa.String(30), nullable=True),
sa.Column('requires_approval', sa.Boolean(), nullable=False, default=False),
sa.Column('approved_by', UUID(as_uuid=True), nullable=True),
sa.Column('approved_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('rejection_reason', sa.Text(), nullable=True),
sa.Column('sent_to_supplier_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('supplier_confirmation_date', sa.DateTime(timezone=True), nullable=True),
sa.Column('supplier_reference', sa.String(100), nullable=True),
sa.Column('notes', sa.Text(), nullable=True),
sa.Column('internal_notes', sa.Text(), nullable=True),
sa.Column('terms_and_conditions', sa.Text(), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('created_by', UUID(as_uuid=True), nullable=False),
sa.Column('updated_by', UUID(as_uuid=True), nullable=False),
sa.ForeignKeyConstraint(['supplier_id'], ['suppliers.id'])
)
# Create purchase_order_items table
op.create_table('purchase_order_items',
sa.Column('id', UUID(as_uuid=True), nullable=False, primary_key=True),
sa.Column('tenant_id', UUID(as_uuid=True), nullable=False),
sa.Column('purchase_order_id', UUID(as_uuid=True), nullable=False),
sa.Column('price_list_item_id', UUID(as_uuid=True), nullable=True),
sa.Column('ingredient_id', UUID(as_uuid=True), nullable=False),
sa.Column('product_code', sa.String(100), nullable=True),
sa.Column('product_name', sa.String(255), nullable=False),
sa.Column('ordered_quantity', sa.Integer(), nullable=False),
sa.Column('unit_of_measure', sa.String(20), nullable=False),
sa.Column('unit_price', sa.Numeric(10, 4), nullable=False),
sa.Column('line_total', sa.Numeric(12, 2), nullable=False),
sa.Column('received_quantity', sa.Integer(), nullable=False, default=0),
sa.Column('remaining_quantity', sa.Integer(), nullable=False, default=0),
sa.Column('quality_requirements', sa.Text(), nullable=True),
sa.Column('item_notes', sa.Text(), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
sa.ForeignKeyConstraint(['purchase_order_id'], ['purchase_orders.id']),
sa.ForeignKeyConstraint(['price_list_item_id'], ['supplier_price_lists.id'])
)
# Create deliveries table
op.create_table('deliveries',
sa.Column('id', UUID(as_uuid=True), nullable=False, primary_key=True),
sa.Column('tenant_id', UUID(as_uuid=True), nullable=False),
sa.Column('purchase_order_id', UUID(as_uuid=True), nullable=False),
sa.Column('supplier_id', UUID(as_uuid=True), nullable=False),
sa.Column('delivery_number', sa.String(50), nullable=False),
sa.Column('supplier_delivery_note', sa.String(100), nullable=True),
sa.Column('status', sa.Enum('SCHEDULED', 'IN_TRANSIT', 'OUT_FOR_DELIVERY', 'DELIVERED', 'PARTIALLY_DELIVERED', 'FAILED_DELIVERY', 'RETURNED', name='deliverystatus'), nullable=False, default='SCHEDULED'),
sa.Column('scheduled_date', sa.DateTime(timezone=True), nullable=True),
sa.Column('estimated_arrival', sa.DateTime(timezone=True), nullable=True),
sa.Column('actual_arrival', sa.DateTime(timezone=True), nullable=True),
sa.Column('completed_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('delivery_address', sa.Text(), nullable=True),
sa.Column('delivery_contact', sa.String(200), nullable=True),
sa.Column('delivery_phone', sa.String(30), nullable=True),
sa.Column('carrier_name', sa.String(200), nullable=True),
sa.Column('tracking_number', sa.String(100), nullable=True),
sa.Column('inspection_passed', sa.Boolean(), nullable=True),
sa.Column('inspection_notes', sa.Text(), nullable=True),
sa.Column('quality_issues', JSONB, nullable=True),
sa.Column('received_by', UUID(as_uuid=True), nullable=True),
sa.Column('received_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('notes', sa.Text(), nullable=True),
sa.Column('photos', JSONB, nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('created_by', UUID(as_uuid=True), nullable=False),
sa.ForeignKeyConstraint(['purchase_order_id'], ['purchase_orders.id']),
sa.ForeignKeyConstraint(['supplier_id'], ['suppliers.id'])
)
# Create delivery_items table
op.create_table('delivery_items',
sa.Column('id', UUID(as_uuid=True), nullable=False, primary_key=True),
sa.Column('tenant_id', UUID(as_uuid=True), nullable=False),
sa.Column('delivery_id', UUID(as_uuid=True), nullable=False),
sa.Column('purchase_order_item_id', UUID(as_uuid=True), nullable=False),
sa.Column('ingredient_id', UUID(as_uuid=True), nullable=False),
sa.Column('product_name', sa.String(255), nullable=False),
sa.Column('ordered_quantity', sa.Integer(), nullable=False),
sa.Column('delivered_quantity', sa.Integer(), nullable=False),
sa.Column('accepted_quantity', sa.Integer(), nullable=False),
sa.Column('rejected_quantity', sa.Integer(), nullable=False, default=0),
sa.Column('batch_lot_number', sa.String(100), nullable=True),
sa.Column('expiry_date', sa.DateTime(timezone=True), nullable=True),
sa.Column('quality_grade', sa.String(20), nullable=True),
sa.Column('quality_issues', sa.Text(), nullable=True),
sa.Column('rejection_reason', sa.Text(), nullable=True),
sa.Column('item_notes', sa.Text(), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
sa.ForeignKeyConstraint(['delivery_id'], ['deliveries.id']),
sa.ForeignKeyConstraint(['purchase_order_item_id'], ['purchase_order_items.id'])
)
# Create supplier_quality_reviews table
op.create_table('supplier_quality_reviews',
sa.Column('id', UUID(as_uuid=True), nullable=False, primary_key=True),
sa.Column('tenant_id', UUID(as_uuid=True), nullable=False),
sa.Column('supplier_id', UUID(as_uuid=True), nullable=False),
sa.Column('purchase_order_id', UUID(as_uuid=True), nullable=True),
sa.Column('delivery_id', UUID(as_uuid=True), nullable=True),
sa.Column('review_date', sa.DateTime(timezone=True), nullable=False),
sa.Column('review_type', sa.String(50), nullable=False),
sa.Column('quality_rating', sa.Enum('EXCELLENT', 'GOOD', 'AVERAGE', 'POOR', 'VERY_POOR', name='qualityrating'), nullable=False),
sa.Column('delivery_rating', sa.Enum('EXCELLENT', 'GOOD', 'AVERAGE', 'POOR', 'VERY_POOR', name='deliveryrating'), nullable=False),
sa.Column('communication_rating', sa.Integer(), nullable=False),
sa.Column('overall_rating', sa.Float(), nullable=False),
sa.Column('quality_comments', sa.Text(), nullable=True),
sa.Column('delivery_comments', sa.Text(), nullable=True),
sa.Column('communication_comments', sa.Text(), nullable=True),
sa.Column('improvement_suggestions', sa.Text(), nullable=True),
sa.Column('quality_issues', JSONB, nullable=True),
sa.Column('corrective_actions', sa.Text(), nullable=True),
sa.Column('follow_up_required', sa.Boolean(), nullable=False, default=False),
sa.Column('follow_up_date', sa.DateTime(timezone=True), nullable=True),
sa.Column('is_final', sa.Boolean(), nullable=False, default=True),
sa.Column('approved_by', UUID(as_uuid=True), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('reviewed_by', UUID(as_uuid=True), nullable=False),
sa.ForeignKeyConstraint(['supplier_id'], ['suppliers.id']),
sa.ForeignKeyConstraint(['purchase_order_id'], ['purchase_orders.id']),
sa.ForeignKeyConstraint(['delivery_id'], ['deliveries.id'])
)
# Create supplier_invoices table
op.create_table('supplier_invoices',
sa.Column('id', UUID(as_uuid=True), nullable=False, primary_key=True),
sa.Column('tenant_id', UUID(as_uuid=True), nullable=False),
sa.Column('supplier_id', UUID(as_uuid=True), nullable=False),
sa.Column('purchase_order_id', UUID(as_uuid=True), nullable=True),
sa.Column('invoice_number', sa.String(50), nullable=False),
sa.Column('supplier_invoice_number', sa.String(100), nullable=False),
sa.Column('status', sa.Enum('PENDING', 'APPROVED', 'PAID', 'OVERDUE', 'DISPUTED', 'CANCELLED', name='invoicestatus'), nullable=False, default='PENDING'),
sa.Column('invoice_date', sa.DateTime(timezone=True), nullable=False),
sa.Column('due_date', sa.DateTime(timezone=True), nullable=False),
sa.Column('received_date', sa.DateTime(timezone=True), nullable=False),
sa.Column('subtotal', sa.Numeric(12, 2), nullable=False),
sa.Column('tax_amount', sa.Numeric(12, 2), nullable=False, default=0.0),
sa.Column('shipping_cost', sa.Numeric(10, 2), nullable=False, default=0.0),
sa.Column('discount_amount', sa.Numeric(10, 2), nullable=False, default=0.0),
sa.Column('total_amount', sa.Numeric(12, 2), nullable=False),
sa.Column('currency', sa.String(3), nullable=False, default='EUR'),
sa.Column('paid_amount', sa.Numeric(12, 2), nullable=False, default=0.0),
sa.Column('payment_date', sa.DateTime(timezone=True), nullable=True),
sa.Column('payment_reference', sa.String(100), nullable=True),
sa.Column('approved_by', UUID(as_uuid=True), nullable=True),
sa.Column('approved_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('rejection_reason', sa.Text(), nullable=True),
sa.Column('notes', sa.Text(), nullable=True),
sa.Column('invoice_document_url', sa.String(500), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('created_by', UUID(as_uuid=True), nullable=False),
sa.ForeignKeyConstraint(['supplier_id'], ['suppliers.id']),
sa.ForeignKeyConstraint(['purchase_order_id'], ['purchase_orders.id'])
)
# Create indexes
op.create_index('ix_suppliers_tenant_id', 'suppliers', ['tenant_id'])
op.create_index('ix_suppliers_name', 'suppliers', ['name'])
op.create_index('ix_suppliers_tenant_name', 'suppliers', ['tenant_id', 'name'])
op.create_index('ix_suppliers_tenant_status', 'suppliers', ['tenant_id', 'status'])
op.create_index('ix_suppliers_tenant_type', 'suppliers', ['tenant_id', 'supplier_type'])
op.create_index('ix_suppliers_quality_rating', 'suppliers', ['quality_rating'])
op.create_index('ix_suppliers_status', 'suppliers', ['status'])
op.create_index('ix_suppliers_supplier_type', 'suppliers', ['supplier_type'])
op.create_index('ix_price_lists_tenant_id', 'supplier_price_lists', ['tenant_id'])
op.create_index('ix_price_lists_supplier_id', 'supplier_price_lists', ['supplier_id'])
op.create_index('ix_price_lists_tenant_supplier', 'supplier_price_lists', ['tenant_id', 'supplier_id'])
op.create_index('ix_price_lists_ingredient', 'supplier_price_lists', ['ingredient_id'])
op.create_index('ix_price_lists_active', 'supplier_price_lists', ['is_active'])
op.create_index('ix_price_lists_effective_date', 'supplier_price_lists', ['effective_date'])
op.create_index('ix_purchase_orders_tenant_id', 'purchase_orders', ['tenant_id'])
op.create_index('ix_purchase_orders_supplier_id', 'purchase_orders', ['supplier_id'])
op.create_index('ix_purchase_orders_tenant_supplier', 'purchase_orders', ['tenant_id', 'supplier_id'])
op.create_index('ix_purchase_orders_tenant_status', 'purchase_orders', ['tenant_id', 'status'])
op.create_index('ix_purchase_orders_po_number', 'purchase_orders', ['po_number'])
op.create_index('ix_purchase_orders_order_date', 'purchase_orders', ['order_date'])
op.create_index('ix_purchase_orders_delivery_date', 'purchase_orders', ['required_delivery_date'])
op.create_index('ix_purchase_orders_status', 'purchase_orders', ['status'])
op.create_index('ix_po_items_tenant_id', 'purchase_order_items', ['tenant_id'])
op.create_index('ix_po_items_purchase_order_id', 'purchase_order_items', ['purchase_order_id'])
op.create_index('ix_po_items_tenant_po', 'purchase_order_items', ['tenant_id', 'purchase_order_id'])
op.create_index('ix_po_items_ingredient', 'purchase_order_items', ['ingredient_id'])
op.create_index('ix_deliveries_tenant_id', 'deliveries', ['tenant_id'])
op.create_index('ix_deliveries_tenant_status', 'deliveries', ['tenant_id', 'status'])
op.create_index('ix_deliveries_scheduled_date', 'deliveries', ['scheduled_date'])
op.create_index('ix_deliveries_delivery_number', 'deliveries', ['delivery_number'])
op.create_index('ix_delivery_items_tenant_id', 'delivery_items', ['tenant_id'])
op.create_index('ix_delivery_items_delivery_id', 'delivery_items', ['delivery_id'])
op.create_index('ix_delivery_items_tenant_delivery', 'delivery_items', ['tenant_id', 'delivery_id'])
op.create_index('ix_delivery_items_ingredient', 'delivery_items', ['ingredient_id'])
op.create_index('ix_quality_reviews_tenant_id', 'supplier_quality_reviews', ['tenant_id'])
op.create_index('ix_quality_reviews_supplier_id', 'supplier_quality_reviews', ['supplier_id'])
op.create_index('ix_quality_reviews_tenant_supplier', 'supplier_quality_reviews', ['tenant_id', 'supplier_id'])
op.create_index('ix_quality_reviews_date', 'supplier_quality_reviews', ['review_date'])
op.create_index('ix_quality_reviews_overall_rating', 'supplier_quality_reviews', ['overall_rating'])
op.create_index('ix_invoices_tenant_id', 'supplier_invoices', ['tenant_id'])
op.create_index('ix_invoices_supplier_id', 'supplier_invoices', ['supplier_id'])
op.create_index('ix_invoices_tenant_supplier', 'supplier_invoices', ['tenant_id', 'supplier_id'])
op.create_index('ix_invoices_tenant_status', 'supplier_invoices', ['tenant_id', 'status'])
op.create_index('ix_invoices_due_date', 'supplier_invoices', ['due_date'])
op.create_index('ix_invoices_invoice_number', 'supplier_invoices', ['invoice_number'])
def downgrade() -> None:
# Drop indexes
op.drop_index('ix_invoices_invoice_number', 'supplier_invoices')
op.drop_index('ix_invoices_due_date', 'supplier_invoices')
op.drop_index('ix_invoices_tenant_status', 'supplier_invoices')
op.drop_index('ix_invoices_tenant_supplier', 'supplier_invoices')
op.drop_index('ix_invoices_supplier_id', 'supplier_invoices')
op.drop_index('ix_invoices_tenant_id', 'supplier_invoices')
op.drop_index('ix_quality_reviews_overall_rating', 'supplier_quality_reviews')
op.drop_index('ix_quality_reviews_date', 'supplier_quality_reviews')
op.drop_index('ix_quality_reviews_tenant_supplier', 'supplier_quality_reviews')
op.drop_index('ix_quality_reviews_supplier_id', 'supplier_quality_reviews')
op.drop_index('ix_quality_reviews_tenant_id', 'supplier_quality_reviews')
op.drop_index('ix_delivery_items_ingredient', 'delivery_items')
op.drop_index('ix_delivery_items_tenant_delivery', 'delivery_items')
op.drop_index('ix_delivery_items_delivery_id', 'delivery_items')
op.drop_index('ix_delivery_items_tenant_id', 'delivery_items')
op.drop_index('ix_deliveries_delivery_number', 'deliveries')
op.drop_index('ix_deliveries_scheduled_date', 'deliveries')
op.drop_index('ix_deliveries_tenant_status', 'deliveries')
op.drop_index('ix_deliveries_tenant_id', 'deliveries')
op.drop_index('ix_po_items_ingredient', 'purchase_order_items')
op.drop_index('ix_po_items_tenant_po', 'purchase_order_items')
op.drop_index('ix_po_items_purchase_order_id', 'purchase_order_items')
op.drop_index('ix_po_items_tenant_id', 'purchase_order_items')
op.drop_index('ix_purchase_orders_status', 'purchase_orders')
op.drop_index('ix_purchase_orders_delivery_date', 'purchase_orders')
op.drop_index('ix_purchase_orders_order_date', 'purchase_orders')
op.drop_index('ix_purchase_orders_po_number', 'purchase_orders')
op.drop_index('ix_purchase_orders_tenant_status', 'purchase_orders')
op.drop_index('ix_purchase_orders_tenant_supplier', 'purchase_orders')
op.drop_index('ix_purchase_orders_supplier_id', 'purchase_orders')
op.drop_index('ix_purchase_orders_tenant_id', 'purchase_orders')
op.drop_index('ix_price_lists_effective_date', 'supplier_price_lists')
op.drop_index('ix_price_lists_active', 'supplier_price_lists')
op.drop_index('ix_price_lists_ingredient', 'supplier_price_lists')
op.drop_index('ix_price_lists_tenant_supplier', 'supplier_price_lists')
op.drop_index('ix_price_lists_supplier_id', 'supplier_price_lists')
op.drop_index('ix_price_lists_tenant_id', 'supplier_price_lists')
op.drop_index('ix_suppliers_supplier_type', 'suppliers')
op.drop_index('ix_suppliers_status', 'suppliers')
op.drop_index('ix_suppliers_quality_rating', 'suppliers')
op.drop_index('ix_suppliers_tenant_type', 'suppliers')
op.drop_index('ix_suppliers_tenant_status', 'suppliers')
op.drop_index('ix_suppliers_tenant_name', 'suppliers')
op.drop_index('ix_suppliers_name', 'suppliers')
op.drop_index('ix_suppliers_tenant_id', 'suppliers')
# Drop tables
op.drop_table('supplier_invoices')
op.drop_table('supplier_quality_reviews')
op.drop_table('delivery_items')
op.drop_table('deliveries')
op.drop_table('purchase_order_items')
op.drop_table('purchase_orders')
op.drop_table('supplier_price_lists')
op.drop_table('suppliers')
# Drop enums
op.execute('DROP TYPE IF EXISTS invoicestatus')
op.execute('DROP TYPE IF EXISTS deliveryrating')
op.execute('DROP TYPE IF EXISTS qualityrating')
op.execute('DROP TYPE IF EXISTS deliverystatus')
op.execute('DROP TYPE IF EXISTS purchaseorderstatus')
op.execute('DROP TYPE IF EXISTS paymentterms')
op.execute('DROP TYPE IF EXISTS supplierstatus')
op.execute('DROP TYPE IF EXISTS suppliertype')

View File

@@ -0,0 +1,151 @@
"""Standardize product references to inventory_product_id
Revision ID: 001_standardize_product_references
Revises:
Create Date: 2025-01-15 12:00:00.000000
This migration standardizes product references across the suppliers service by:
1. Renaming ingredient_id columns to inventory_product_id
2. Removing redundant product_name columns where UUID references exist
3. Updating indexes to match new column names
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import UUID
# revision identifiers
revision = '001_standardize_product_references'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
"""Apply the changes to standardize product references"""
# 1. Update supplier_price_lists table
print("Updating supplier_price_lists table...")
# Rename ingredient_id to inventory_product_id
op.alter_column('supplier_price_lists', 'ingredient_id',
new_column_name='inventory_product_id')
# Drop the product_name column (redundant with UUID reference)
op.drop_column('supplier_price_lists', 'product_name')
# Update index name
op.drop_index('ix_price_lists_ingredient')
op.create_index('ix_price_lists_inventory_product', 'supplier_price_lists',
['inventory_product_id'])
# 2. Update purchase_order_items table
print("Updating purchase_order_items table...")
# Rename ingredient_id to inventory_product_id
op.alter_column('purchase_order_items', 'ingredient_id',
new_column_name='inventory_product_id')
# Drop the product_name column (redundant with UUID reference)
op.drop_column('purchase_order_items', 'product_name')
# Update index name
op.drop_index('ix_po_items_ingredient')
op.create_index('ix_po_items_inventory_product', 'purchase_order_items',
['inventory_product_id'])
# 3. Update delivery_items table
print("Updating delivery_items table...")
# Rename ingredient_id to inventory_product_id
op.alter_column('delivery_items', 'ingredient_id',
new_column_name='inventory_product_id')
# Drop the product_name column (redundant with UUID reference)
op.drop_column('delivery_items', 'product_name')
# Update index name
op.drop_index('ix_delivery_items_ingredient')
op.create_index('ix_delivery_items_inventory_product', 'delivery_items',
['inventory_product_id'])
print("Migration completed successfully!")
def downgrade():
"""Revert the changes (for rollback purposes)"""
print("Rolling back product reference standardization...")
# 1. Revert delivery_items table
print("Reverting delivery_items table...")
# Revert index name
op.drop_index('ix_delivery_items_inventory_product')
op.create_index('ix_delivery_items_ingredient', 'delivery_items',
['inventory_product_id']) # Will rename back to ingredient_id below
# Add back product_name column (will be empty initially)
op.add_column('delivery_items',
sa.Column('product_name', sa.String(255), nullable=False,
server_default='Unknown Product'))
# Rename inventory_product_id back to ingredient_id
op.alter_column('delivery_items', 'inventory_product_id',
new_column_name='ingredient_id')
# Update index to use ingredient_id
op.drop_index('ix_delivery_items_ingredient')
op.create_index('ix_delivery_items_ingredient', 'delivery_items',
['ingredient_id'])
# 2. Revert purchase_order_items table
print("Reverting purchase_order_items table...")
# Revert index name
op.drop_index('ix_po_items_inventory_product')
op.create_index('ix_po_items_ingredient', 'purchase_order_items',
['inventory_product_id']) # Will rename back to ingredient_id below
# Add back product_name column (will be empty initially)
op.add_column('purchase_order_items',
sa.Column('product_name', sa.String(255), nullable=False,
server_default='Unknown Product'))
# Rename inventory_product_id back to ingredient_id
op.alter_column('purchase_order_items', 'inventory_product_id',
new_column_name='ingredient_id')
# Update index to use ingredient_id
op.drop_index('ix_po_items_ingredient')
op.create_index('ix_po_items_ingredient', 'purchase_order_items',
['ingredient_id'])
# 3. Revert supplier_price_lists table
print("Reverting supplier_price_lists table...")
# Revert index name
op.drop_index('ix_price_lists_inventory_product')
op.create_index('ix_price_lists_ingredient', 'supplier_price_lists',
['inventory_product_id']) # Will rename back to ingredient_id below
# Add back product_name column (will be empty initially)
op.add_column('supplier_price_lists',
sa.Column('product_name', sa.String(255), nullable=False,
server_default='Unknown Product'))
# Rename inventory_product_id back to ingredient_id
op.alter_column('supplier_price_lists', 'inventory_product_id',
new_column_name='ingredient_id')
# Update index to use ingredient_id
op.drop_index('ix_price_lists_ingredient')
op.create_index('ix_price_lists_ingredient', 'supplier_price_lists',
['ingredient_id'])
print("Rollback completed successfully!")