# restructure_models.ps1 - PowerShell script to restructure models from single files to domain-organized structure Write-Host "🔄 Starting models restructure..." -ForegroundColor Cyan # Create new directory structure for models Write-Host "📁 Creating models directory structure..." -ForegroundColor Yellow $modelDirectories = @( "models\database", "models\api" ) foreach ($dir in $modelDirectories) { New-Item -Path $dir -ItemType Directory -Force | Out-Null Write-Host " Created: $dir" -ForegroundColor Gray } # Backup original model files Write-Host "💾 Backing up original model files..." -ForegroundColor Yellow New-Item -Path "models\backup" -ItemType Directory -Force | Out-Null $originalFiles = @("models\database_models.py", "models\api_models.py") foreach ($file in $originalFiles) { if (Test-Path $file) { Copy-Item $file "models\backup\" -Force Write-Host " Backed up: $(Split-Path $file -Leaf)" -ForegroundColor Gray } } # Create database models files Write-Host "📄 Creating database model files..." -ForegroundColor Yellow # models/database/__init__.py $databaseInit = @" # models/database/__init__.py from .user import User from .product import Product from .shop import Shop, ShopProduct from .stock import Stock from .marketplace import MarketplaceImportJob __all__ = [ "User", "Product", "Shop", "ShopProduct", "Stock", "MarketplaceImportJob", ] "@ $databaseInit | Out-File -FilePath "models\database\__init__.py" -Encoding UTF8 # models/database/base.py $databaseBase = @" # models/database/base.py from datetime import datetime from sqlalchemy import Column, DateTime from app.core.database import Base class TimestampMixin: """Mixin to add created_at and updated_at timestamps to models""" created_at = Column(DateTime, default=datetime.utcnow, nullable=False) updated_at = Column( DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False ) "@ $databaseBase | Out-File -FilePath "models\database\base.py" -Encoding UTF8 # models/database/user.py $userModel = @" # models/database/user.py from datetime import datetime from sqlalchemy import Boolean, Column, DateTime, Integer, String from sqlalchemy.orm import relationship from app.core.database import Base class User(Base): __tablename__ = "users" id = Column(Integer, primary_key=True, index=True) email = Column(String, unique=True, index=True, nullable=False) username = Column(String, unique=True, index=True, nullable=False) hashed_password = Column(String, nullable=False) role = Column(String, nullable=False, default="user") # user, admin, shop_owner is_active = Column(Boolean, default=True, nullable=False) last_login = Column(DateTime, nullable=True) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) updated_at = Column( DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False ) # Relationships marketplace_import_jobs = relationship( "MarketplaceImportJob", back_populates="user" ) owned_shops = relationship("Shop", back_populates="owner") def __repr__(self): return f"" "@ $userModel | Out-File -FilePath "models\database\user.py" -Encoding UTF8 # models/database/product.py $productModel = @" # models/database/product.py from datetime import datetime from sqlalchemy import Column, DateTime, Index, Integer, String from sqlalchemy.orm import relationship from app.core.database import Base class Product(Base): __tablename__ = "products" id = Column(Integer, primary_key=True, index=True) product_id = Column(String, unique=True, index=True, nullable=False) title = Column(String, nullable=False) description = Column(String) link = Column(String) image_link = Column(String) availability = Column(String, index=True) # Index for filtering price = Column(String) brand = Column(String, index=True) # Index for filtering gtin = Column(String, index=True) # Index for stock lookups mpn = Column(String) condition = Column(String) adult = Column(String) multipack = Column(Integer) is_bundle = Column(String) age_group = Column(String) color = Column(String) gender = Column(String) material = Column(String) pattern = Column(String) size = Column(String) size_type = Column(String) size_system = Column(String) item_group_id = Column(String) google_product_category = Column(String, index=True) # Index for filtering product_type = Column(String) custom_label_0 = Column(String) custom_label_1 = Column(String) custom_label_2 = Column(String) custom_label_3 = Column(String) custom_label_4 = Column(String) additional_image_link = Column(String) sale_price = Column(String) unit_pricing_measure = Column(String) unit_pricing_base_measure = Column(String) identifier_exists = Column(String) shipping = Column(String) currency = Column(String) # New marketplace fields marketplace = Column( String, index=True, nullable=True, default="Letzshop" ) # Index for marketplace filtering shop_name = Column(String, index=True, nullable=True) # Index for shop filtering created_at = Column(DateTime, default=datetime.utcnow, nullable=False) updated_at = Column( DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False ) # Relationship to stock (one-to-many via GTIN) stock_entries = relationship( "Stock", foreign_keys="Stock.gtin", primaryjoin="Product.gtin == Stock.gtin", viewonly=True, ) shop_products = relationship("ShopProduct", back_populates="product") # Additional indexes for marketplace queries __table_args__ = ( Index( "idx_marketplace_shop", "marketplace", "shop_name" ), # Composite index for marketplace+shop queries Index( "idx_marketplace_brand", "marketplace", "brand" ), # Composite index for marketplace+brand queries ) def __repr__(self): return ( f"" ) "@ $productModel | Out-File -FilePath "models\database\product.py" -Encoding UTF8 # models/database/shop.py $shopModel = @" # models/database/shop.py from datetime import datetime from sqlalchemy import Boolean, Column, DateTime, Float, ForeignKey, Index, Integer, String, Text, UniqueConstraint from sqlalchemy.orm import relationship from app.core.database import Base class Shop(Base): __tablename__ = "shops" id = Column(Integer, primary_key=True, index=True) shop_code = Column( String, unique=True, index=True, nullable=False ) # e.g., "TECHSTORE", "FASHIONHUB" shop_name = Column(String, nullable=False) # Display name description = Column(Text) owner_id = Column(Integer, ForeignKey("users.id"), nullable=False) # Contact information contact_email = Column(String) contact_phone = Column(String) website = Column(String) # Business information business_address = Column(Text) tax_number = Column(String) # Status is_active = Column(Boolean, default=True) is_verified = Column(Boolean, default=False) # Timestamps created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # Relationships owner = relationship("User", back_populates="owned_shops") shop_products = relationship("ShopProduct", back_populates="shop") marketplace_import_jobs = relationship( "MarketplaceImportJob", back_populates="shop" ) class ShopProduct(Base): __tablename__ = "shop_products" id = Column(Integer, primary_key=True, index=True) shop_id = Column(Integer, ForeignKey("shops.id"), nullable=False) product_id = Column(Integer, ForeignKey("products.id"), nullable=False) # Shop-specific overrides (can override the main product data) shop_product_id = Column(String) # Shop's internal product ID shop_price = Column(Float) # Override main product price shop_sale_price = Column(Float) shop_currency = Column(String) shop_availability = Column(String) # Override availability shop_condition = Column(String) # Shop-specific metadata is_featured = Column(Boolean, default=False) is_active = Column(Boolean, default=True) display_order = Column(Integer, default=0) # Inventory management min_quantity = Column(Integer, default=1) max_quantity = Column(Integer) # Timestamps created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # Relationships shop = relationship("Shop", back_populates="shop_products") product = relationship("Product", back_populates="shop_products") # Constraints __table_args__ = ( UniqueConstraint("shop_id", "product_id", name="uq_shop_product"), Index("idx_shop_product_active", "shop_id", "is_active"), Index("idx_shop_product_featured", "shop_id", "is_featured"), ) "@ $shopModel | Out-File -FilePath "models\database\shop.py" -Encoding UTF8 # models/database/stock.py $stockModel = @" # models/database/stock.py from datetime import datetime from sqlalchemy import Column, DateTime, ForeignKey, Index, Integer, String, UniqueConstraint from sqlalchemy.orm import relationship from app.core.database import Base class Stock(Base): __tablename__ = "stock" id = Column(Integer, primary_key=True, index=True) gtin = Column( String, index=True, nullable=False ) # Foreign key relationship would be ideal location = Column(String, nullable=False, index=True) quantity = Column(Integer, nullable=False, default=0) reserved_quantity = Column(Integer, default=0) # For orders being processed shop_id = Column(Integer, ForeignKey("shops.id")) # Optional: shop-specific stock created_at = Column(DateTime, default=datetime.utcnow, nullable=False) updated_at = Column( DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False ) # Relationships shop = relationship("Shop") # Composite unique constraint to prevent duplicate GTIN-location combinations __table_args__ = ( UniqueConstraint("gtin", "location", name="uq_stock_gtin_location"), Index( "idx_stock_gtin_location", "gtin", "location" ), # Composite index for efficient queries ) def __repr__(self): return f"" "@ $stockModel | Out-File -FilePath "models\database\stock.py" -Encoding UTF8 # models/database/marketplace.py $marketplaceModel = @" # models/database/marketplace.py from datetime import datetime from sqlalchemy import Column, DateTime, ForeignKey, Index, Integer, String from sqlalchemy.orm import relationship from app.core.database import Base class MarketplaceImportJob(Base): __tablename__ = "marketplace_import_jobs" id = Column(Integer, primary_key=True, index=True) status = Column( String, nullable=False, default="pending" ) # pending, processing, completed, failed, completed_with_errors source_url = Column(String, nullable=False) marketplace = Column( String, nullable=False, index=True, default="Letzshop" ) # Index for marketplace filtering shop_name = Column(String, nullable=False, index=True) # Index for shop filtering shop_id = Column( Integer, ForeignKey("shops.id"), nullable=False ) # Add proper foreign key user_id = Column( Integer, ForeignKey("users.id"), nullable=False ) # Foreign key to users table # Results imported_count = Column(Integer, default=0) updated_count = Column(Integer, default=0) error_count = Column(Integer, default=0) total_processed = Column(Integer, default=0) # Error handling error_message = Column(String) # Timestamps created_at = Column(DateTime, default=datetime.utcnow, nullable=False) started_at = Column(DateTime) completed_at = Column(DateTime) # Relationship to user user = relationship("User", foreign_keys=[user_id]) shop = relationship("Shop", back_populates="marketplace_import_jobs") # Additional indexes for marketplace import job queries __table_args__ = ( Index( "idx_marketplace_import_user_marketplace", "user_id", "marketplace" ), # User's marketplace imports Index("idx_marketplace_import_shop_status", "status"), # Shop import status Index("idx_marketplace_import_shop_id", "shop_id"), ) def __repr__(self): return ( f"" ) "@ $marketplaceModel | Out-File -FilePath "models\database\marketplace.py" -Encoding UTF8 # Create API models files Write-Host "📄 Creating API model files..." -ForegroundColor Yellow # models/api/__init__.py $apiInit = @" # models/api/__init__.py from .auth import UserRegister, UserLogin, UserResponse, LoginResponse from .product import ProductBase, ProductCreate, ProductUpdate, ProductResponse, ProductListResponse, ProductDetailResponse from .shop import ShopCreate, ShopUpdate, ShopResponse, ShopListResponse, ShopProductCreate, ShopProductResponse from .stock import StockBase, StockCreate, StockAdd, StockUpdate, StockResponse, StockLocationResponse, StockSummaryResponse from .marketplace import MarketplaceImportRequest, MarketplaceImportJobResponse from .stats import StatsResponse, MarketplaceStatsResponse __all__ = [ # Auth models "UserRegister", "UserLogin", "UserResponse", "LoginResponse", # Product models "ProductBase", "ProductCreate", "ProductUpdate", "ProductResponse", "ProductListResponse", "ProductDetailResponse", # Shop models "ShopCreate", "ShopUpdate", "ShopResponse", "ShopListResponse", "ShopProductCreate", "ShopProductResponse", # Stock models "StockBase", "StockCreate", "StockAdd", "StockUpdate", "StockResponse", "StockLocationResponse", "StockSummaryResponse", # Marketplace models "MarketplaceImportRequest", "MarketplaceImportJobResponse", # Stats models "StatsResponse", "MarketplaceStatsResponse", ] "@ $apiInit | Out-File -FilePath "models\api\__init__.py" -Encoding UTF8 # models/api/base.py $apiBase = @" # models/api/base.py from typing import List, TypeVar, Generic from pydantic import BaseModel T = TypeVar('T') class ListResponse(BaseModel, Generic[T]): """Generic list response model""" items: List[T] total: int skip: int limit: int class StatusResponse(BaseModel): """Generic status response""" success: bool message: str "@ $apiBase | Out-File -FilePath "models\api\base.py" -Encoding UTF8 Write-Host "✅ Models directory structure created!" -ForegroundColor Green Write-Host "" Write-Host "📋 Next steps:" -ForegroundColor Cyan Write-Host "1. You'll need to manually extract the remaining API model classes from api_models.py:" -ForegroundColor White Write-Host " - Auth models → models\api\auth.py" -ForegroundColor Gray Write-Host " - Product models → models\api\product.py" -ForegroundColor Gray Write-Host " - Shop models → models\api\shop.py" -ForegroundColor Gray Write-Host " - Stock models → models\api\stock.py" -ForegroundColor Gray Write-Host " - Marketplace models → models\api\marketplace.py" -ForegroundColor Gray Write-Host " - Stats models → models\api\stats.py" -ForegroundColor Gray Write-Host "" Write-Host "2. Update imports throughout your application:" -ForegroundColor White Write-Host " Old: from models.database_models import User, Product" -ForegroundColor Gray Write-Host " New: from models.database import User, Product" -ForegroundColor Gray Write-Host "" Write-Host " Old: from models.api_models import UserCreate, ProductResponse" -ForegroundColor Gray Write-Host " New: from models.api import UserRegister, ProductResponse" -ForegroundColor Gray Write-Host "" Write-Host "3. Test imports after restructure:" -ForegroundColor White Write-Host " python -c \"from models.database import User, Product, Shop\"" -ForegroundColor Yellow Write-Host " python -c \"from models.api import UserRegister, ProductResponse\"" -ForegroundColor Yellow Write-Host "" Write-Host "4. Files to update (search and replace imports):" -ForegroundColor White Write-Host " - All route files in api/v1/" -ForegroundColor Gray Write-Host " - Service files in app/services/" -ForegroundColor Gray Write-Host " - Test files" -ForegroundColor Gray Write-Host " - Any utility files" -ForegroundColor Gray Write-Host "" Write-Host "✨ Database models restructure completed!" -ForegroundColor Green Write-Host "📚 Original files backed up in models\backup\" -ForegroundColor Green