# services/tenant/app/schemas/tenants.py """ Tenant schemas - FIXED VERSION """ from pydantic import BaseModel, Field, validator from typing import Optional, List, Dict, Any from datetime import datetime from uuid import UUID import re class BakeryRegistration(BaseModel): """Bakery registration schema""" name: str = Field(..., min_length=2, max_length=200) address: str = Field(..., min_length=10, max_length=500) city: str = Field(default="Madrid", max_length=100) postal_code: str = Field(..., pattern=r"^\d{5}$") phone: str = Field(..., min_length=9, max_length=20) business_type: str = Field(default="bakery") @validator('phone') def validate_spanish_phone(cls, v): """Validate Spanish phone number""" # Remove spaces and common separators phone = re.sub(r'[\s\-\(\)]', '', v) # Spanish mobile: +34 6/7/8/9 + 8 digits # Spanish landline: +34 9 + 8 digits patterns = [ r'^(\+34|0034|34)?[6789]\d{8}$', # Mobile r'^(\+34|0034|34)?9\d{8}$', # Landline ] if not any(re.match(pattern, phone) for pattern in patterns): raise ValueError('Invalid Spanish phone number') return v @validator('business_type') def validate_business_type(cls, v): valid_types = ['bakery', 'coffee_shop', 'pastry_shop', 'restaurant'] if v not in valid_types: raise ValueError(f'Business type must be one of: {valid_types}') return v class TenantResponse(BaseModel): """Tenant response schema - FIXED VERSION""" id: str # ✅ Keep as str for Pydantic validation name: str subdomain: Optional[str] business_type: str address: str city: str postal_code: str phone: Optional[str] is_active: bool subscription_tier: str model_trained: bool last_training_date: Optional[datetime] owner_id: str # ✅ Keep as str for Pydantic validation created_at: datetime # ✅ FIX: Add custom validator to convert UUID to string @validator('id', 'owner_id', pre=True) def convert_uuid_to_string(cls, v): """Convert UUID objects to strings for JSON serialization""" if isinstance(v, UUID): return str(v) return v class Config: from_attributes = True class TenantAccessResponse(BaseModel): """Tenant access verification response""" has_access: bool role: str permissions: List[str] class TenantMemberResponse(BaseModel): """Tenant member response - FIXED VERSION""" id: str user_id: str role: str is_active: bool joined_at: Optional[datetime] # ✅ FIX: Add custom validator to convert UUID to string @validator('id', 'user_id', pre=True) def convert_uuid_to_string(cls, v): """Convert UUID objects to strings for JSON serialization""" if isinstance(v, UUID): return str(v) return v class Config: from_attributes = True class TenantUpdate(BaseModel): """Tenant update schema""" name: Optional[str] = Field(None, min_length=2, max_length=200) address: Optional[str] = Field(None, min_length=10, max_length=500) phone: Optional[str] = None business_type: Optional[str] = None class TenantListResponse(BaseModel): """Response schema for listing tenants""" tenants: List[TenantResponse] total: int page: int per_page: int has_next: bool has_prev: bool class TenantMemberInvitation(BaseModel): """Schema for inviting a member to a tenant""" email: str = Field(..., pattern=r'^[^@]+@[^@]+\.[^@]+$') role: str = Field(..., pattern=r'^(admin|member|viewer)$') message: Optional[str] = Field(None, max_length=500) class TenantMemberUpdate(BaseModel): """Schema for updating tenant member""" role: Optional[str] = Field(None, pattern=r'^(owner|admin|member|viewer)$') is_active: Optional[bool] = None class TenantSubscriptionUpdate(BaseModel): """Schema for updating tenant subscription""" plan: str = Field(..., pattern=r'^(basic|professional|enterprise)$') billing_cycle: str = Field(default="monthly", pattern=r'^(monthly|yearly)$') class TenantStatsResponse(BaseModel): """Tenant statistics response""" tenant_id: str total_members: int active_members: int total_predictions: int models_trained: int last_training_date: Optional[datetime] subscription_plan: str subscription_status: str @validator('tenant_id', pre=True) def convert_uuid_to_string(cls, v): """Convert UUID objects to strings for JSON serialization""" if isinstance(v, UUID): return str(v) return v