system-prompts-and-models-o.../salesflow-saas/backend/app/schemas/schemas.py

386 lines
11 KiB
Python

"""Pydantic schemas for request/response validation."""
from datetime import datetime, date
from typing import Optional, List, Any
from uuid import UUID
from pydantic import BaseModel, Field, ConfigDict
# ── Auth Schemas ────────────────────────────────────────────────
class LoginRequest(BaseModel):
email: str
password: str
class RegisterRequest(BaseModel):
email: str
password: str = Field(min_length=8)
full_name: str
company_name: str
industry: Optional[str] = None
phone: Optional[str] = None
class TokenResponse(BaseModel):
access_token: str
refresh_token: str
token_type: str = "bearer"
expires_in: int
user: "UserResponse"
class RefreshTokenRequest(BaseModel):
refresh_token: str
class PasswordResetRequest(BaseModel):
email: str
class PasswordResetConfirm(BaseModel):
token: str
new_password: str = Field(min_length=8)
# ── User Schemas ────────────────────────────────────────────────
class UserResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: UUID
email: str
full_name: Optional[str] = None
full_name_ar: Optional[str] = None
role: str
phone: Optional[str] = None
is_active: bool
last_login: Optional[datetime] = None
created_at: datetime
class UserUpdate(BaseModel):
full_name: Optional[str] = None
full_name_ar: Optional[str] = None
phone: Optional[str] = None
class UserCreate(BaseModel):
email: str
password: str = Field(min_length=8)
full_name: str
role: str = "agent"
phone: Optional[str] = None
# ── Tenant Schemas ──────────────────────────────────────────────
class TenantResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: UUID
name: str
name_ar: Optional[str] = None
slug: str
industry: Optional[str] = None
plan: str
is_active: bool
created_at: datetime
class TenantUpdate(BaseModel):
name: Optional[str] = None
name_ar: Optional[str] = None
industry: Optional[str] = None
logo_url: Optional[str] = None
phone: Optional[str] = None
email: Optional[str] = None
whatsapp_number: Optional[str] = None
settings: Optional[dict] = None
# ── Lead Schemas ────────────────────────────────────────────────
class LeadCreate(BaseModel):
name: str
phone: Optional[str] = None
email: Optional[str] = None
source: Optional[str] = "manual"
company_name: Optional[str] = None
sector: Optional[str] = None
city: Optional[str] = None
notes: Optional[str] = None
extra_metadata: Optional[dict] = None
class LeadUpdate(BaseModel):
name: Optional[str] = None
phone: Optional[str] = None
email: Optional[str] = None
status: Optional[str] = None
score: Optional[int] = None
assigned_to: Optional[UUID] = None
notes: Optional[str] = None
extra_metadata: Optional[dict] = None
class LeadResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: UUID
tenant_id: UUID
name: str
phone: Optional[str] = None
email: Optional[str] = None
source: Optional[str] = None
status: str
score: int
notes: Optional[str] = None
extra_metadata: Optional[dict] = None
assigned_to: Optional[UUID] = None
created_at: datetime
updated_at: Optional[datetime] = None
class LeadQualifyResponse(BaseModel):
lead_id: UUID
score: int
status: str
reasoning: str
suggested_action: str
bant_analysis: dict
# ── Deal Schemas ────────────────────────────────────────────────
class DealCreate(BaseModel):
title: str
lead_id: Optional[UUID] = None
value: Optional[float] = None
currency: str = "SAR"
stage: str = "new"
probability: int = 0
expected_close_date: Optional[date] = None
notes: Optional[str] = None
class DealUpdate(BaseModel):
title: Optional[str] = None
value: Optional[float] = None
stage: Optional[str] = None
probability: Optional[int] = None
expected_close_date: Optional[date] = None
notes: Optional[str] = None
assigned_to: Optional[UUID] = None
class DealResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: UUID
tenant_id: UUID
lead_id: Optional[UUID] = None
customer_id: Optional[UUID] = None
assigned_to: Optional[UUID] = None
title: str
value: Optional[float] = None
currency: str
stage: str
probability: int
expected_close_date: Optional[date] = None
closed_at: Optional[datetime] = None
notes: Optional[str] = None
created_at: datetime
updated_at: Optional[datetime] = None
# ── Company Schemas ─────────────────────────────────────────────
class CompanyCreate(BaseModel):
name: str
name_ar: Optional[str] = None
website: Optional[str] = None
phone: Optional[str] = None
email: Optional[str] = None
industry: Optional[str] = None
size: Optional[str] = None
city: Optional[str] = None
address: Optional[str] = None
notes: Optional[str] = None
class CompanyResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: UUID
tenant_id: UUID
name: str
name_ar: Optional[str] = None
website: Optional[str] = None
phone: Optional[str] = None
email: Optional[str] = None
industry: Optional[str] = None
size: Optional[str] = None
city: Optional[str] = None
is_active: bool
created_at: datetime
# ── Contact Schemas ─────────────────────────────────────────────
class ContactCreate(BaseModel):
company_id: UUID
full_name: str
role: Optional[str] = None
phone: Optional[str] = None
email: Optional[str] = None
is_decision_maker: bool = False
preferred_language: str = "ar"
preferred_channel: str = "whatsapp"
class ContactResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: UUID
tenant_id: UUID
company_id: UUID
full_name: str
role: Optional[str] = None
phone: Optional[str] = None
email: Optional[str] = None
is_decision_maker: bool
preferred_language: str
preferred_channel: str
created_at: datetime
# ── Meeting Schemas ─────────────────────────────────────────────
class MeetingCreate(BaseModel):
lead_id: Optional[UUID] = None
meeting_type: str = "demo"
meeting_datetime: datetime
duration_minutes: int = 30
client_name: str
client_phone: Optional[str] = None
client_email: Optional[str] = None
client_company: Optional[str] = None
assigned_sales_rep: Optional[UUID] = None
notes: Optional[str] = None
class MeetingUpdate(BaseModel):
meeting_datetime: Optional[datetime] = None
duration_minutes: Optional[int] = None
status: Optional[str] = None
notes: Optional[str] = None
outcome: Optional[str] = None
class MeetingResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: UUID
tenant_id: UUID
lead_id: Optional[UUID] = None
meeting_type: str
meeting_datetime: datetime
duration_minutes: int
client_name: str
client_company: Optional[str] = None
status: str
assigned_sales_rep: Optional[UUID] = None
notes: Optional[str] = None
outcome: Optional[str] = None
created_at: datetime
# ── AI Agent Schemas ────────────────────────────────────────────
class AgentInvokeRequest(BaseModel):
agent_type: str
input_data: dict
lead_id: Optional[UUID] = None
conversation_id: Optional[UUID] = None
async_mode: bool = True
class AgentInvokeResponse(BaseModel):
task_id: Optional[str] = None
agent_type: str
status: str # queued, processing, completed, error
output: Optional[dict] = None
tokens_used: Optional[int] = None
latency_ms: Optional[int] = None
class ConversationResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: UUID
tenant_id: UUID
channel: str
status: str
contact_name: Optional[str] = None
contact_phone: Optional[str] = None
contact_company: Optional[str] = None
messages_count: int
sentiment_score: int
interest_level: int
qualified: bool
meeting_booked: bool
last_message_at: Optional[datetime] = None
created_at: datetime
# ── Affiliate Schemas ───────────────────────────────────────────
class AffiliateCreate(BaseModel):
full_name: str
full_name_ar: Optional[str] = None
email: str
phone: str
whatsapp: Optional[str] = None
city: Optional[str] = None
notes: Optional[str] = None
class AffiliateResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: UUID
full_name: str
full_name_ar: Optional[str] = None
email: str
phone: str
status: str
referral_code: Optional[str] = None
total_leads_generated: int
total_deals_closed: int
total_commission_earned: float
created_at: datetime
# ── Commission Schemas ──────────────────────────────────────────
class CommissionResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: UUID
affiliate_id: UUID
deal_id: UUID
amount: float
rate: float
status: str
approved_at: Optional[datetime] = None
paid_at: Optional[datetime] = None
created_at: datetime
# ── Dashboard Schemas ───────────────────────────────────────────
class DashboardSummary(BaseModel):
total_leads: int = 0
new_leads_today: int = 0
qualified_leads: int = 0
active_conversations: int = 0
meetings_today: int = 0
meetings_this_week: int = 0
total_deals: int = 0
deals_won: int = 0
pipeline_value: float = 0.0
revenue_this_month: float = 0.0
active_affiliates: int = 0
ai_conversations_today: int = 0
class PipelineSummary(BaseModel):
stage: str
count: int
total_value: float
class RevenueMetrics(BaseModel):
period: str
revenue: float
deals_closed: int
avg_deal_size: float
# ── Pagination ──────────────────────────────────────────────────
class PaginatedResponse(BaseModel):
items: List[Any]
total: int
page: int
page_size: int
pages: int