Improve the frontend and fix TODOs
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
Tenant schemas - FIXED VERSION
|
||||
"""
|
||||
|
||||
from pydantic import BaseModel, Field, validator
|
||||
from pydantic import BaseModel, Field, field_validator, ValidationInfo
|
||||
from typing import Optional, List, Dict, Any
|
||||
from datetime import datetime
|
||||
from uuid import UUID
|
||||
@@ -20,31 +20,34 @@ class BakeryRegistration(BaseModel):
|
||||
business_model: Optional[str] = Field(default="individual_bakery")
|
||||
coupon_code: Optional[str] = Field(None, max_length=50, description="Promotional coupon code")
|
||||
|
||||
@validator('phone')
|
||||
@field_validator('phone')
|
||||
@classmethod
|
||||
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')
|
||||
|
||||
@field_validator('business_type')
|
||||
@classmethod
|
||||
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
|
||||
|
||||
@validator('business_model')
|
||||
|
||||
@field_validator('business_model')
|
||||
@classmethod
|
||||
def validate_business_model(cls, v):
|
||||
if v is None:
|
||||
return v
|
||||
@@ -72,7 +75,8 @@ class TenantResponse(BaseModel):
|
||||
created_at: datetime
|
||||
|
||||
# ✅ FIX: Add custom validator to convert UUID to string
|
||||
@validator('id', 'owner_id', pre=True)
|
||||
@field_validator('id', 'owner_id', mode='before')
|
||||
@classmethod
|
||||
def convert_uuid_to_string(cls, v):
|
||||
"""Convert UUID objects to strings for JSON serialization"""
|
||||
if isinstance(v, UUID):
|
||||
@@ -89,21 +93,26 @@ class TenantAccessResponse(BaseModel):
|
||||
permissions: List[str]
|
||||
|
||||
class TenantMemberResponse(BaseModel):
|
||||
"""Tenant member response - FIXED VERSION"""
|
||||
"""Tenant member response - FIXED VERSION with enriched user data"""
|
||||
id: str
|
||||
user_id: str
|
||||
role: str
|
||||
is_active: bool
|
||||
joined_at: Optional[datetime]
|
||||
|
||||
# Enriched user fields (populated via service layer)
|
||||
user_email: Optional[str] = None
|
||||
user_full_name: Optional[str] = None
|
||||
user: Optional[Dict[str, Any]] = None # Full user object for compatibility
|
||||
|
||||
# ✅ FIX: Add custom validator to convert UUID to string
|
||||
@validator('id', 'user_id', pre=True)
|
||||
@field_validator('id', 'user_id', mode='before')
|
||||
@classmethod
|
||||
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
|
||||
|
||||
@@ -135,6 +144,42 @@ class TenantMemberUpdate(BaseModel):
|
||||
role: Optional[str] = Field(None, pattern=r'^(owner|admin|member|viewer)$')
|
||||
is_active: Optional[bool] = None
|
||||
|
||||
class AddMemberWithUserCreate(BaseModel):
|
||||
"""Schema for adding member with optional user creation (pilot phase)"""
|
||||
# For existing users
|
||||
user_id: Optional[str] = Field(None, description="ID of existing user to add")
|
||||
|
||||
# For new user creation
|
||||
create_user: bool = Field(False, description="Whether to create a new user")
|
||||
email: Optional[str] = Field(None, description="Email for new user (if create_user=True)")
|
||||
full_name: Optional[str] = Field(None, min_length=2, max_length=100, description="Full name for new user")
|
||||
password: Optional[str] = Field(None, min_length=8, max_length=128, description="Password for new user")
|
||||
phone: Optional[str] = Field(None, description="Phone number for new user")
|
||||
language: Optional[str] = Field("es", pattern="^(es|en|eu)$", description="Preferred language")
|
||||
timezone: Optional[str] = Field("Europe/Madrid", description="User timezone")
|
||||
|
||||
# Common fields
|
||||
role: str = Field(..., pattern=r'^(admin|member|viewer)$', description="Role in the tenant")
|
||||
|
||||
@field_validator('email', 'full_name', 'password')
|
||||
@classmethod
|
||||
def validate_user_creation_fields(cls, v, info: ValidationInfo):
|
||||
"""Validate that required fields are present when creating a user"""
|
||||
if info.data.get('create_user') and info.field_name in ['email', 'full_name', 'password']:
|
||||
if not v:
|
||||
raise ValueError(f"{info.field_name} is required when create_user is True")
|
||||
return v
|
||||
|
||||
@field_validator('user_id')
|
||||
@classmethod
|
||||
def validate_user_id_or_create(cls, v, info: ValidationInfo):
|
||||
"""Ensure either user_id or create_user is provided"""
|
||||
if not v and not info.data.get('create_user'):
|
||||
raise ValueError("Either user_id or create_user must be provided")
|
||||
if v and info.data.get('create_user'):
|
||||
raise ValueError("Cannot specify both user_id and create_user")
|
||||
return v
|
||||
|
||||
class TenantSubscriptionUpdate(BaseModel):
|
||||
"""Schema for updating tenant subscription"""
|
||||
plan: str = Field(..., pattern=r'^(basic|professional|enterprise)$')
|
||||
@@ -151,7 +196,8 @@ class TenantStatsResponse(BaseModel):
|
||||
subscription_plan: str
|
||||
subscription_status: str
|
||||
|
||||
@validator('tenant_id', pre=True)
|
||||
@field_validator('tenant_id', mode='before')
|
||||
@classmethod
|
||||
def convert_uuid_to_string(cls, v):
|
||||
"""Convert UUID objects to strings for JSON serialization"""
|
||||
if isinstance(v, UUID):
|
||||
|
||||
Reference in New Issue
Block a user