bmc_hub/app/models/schemas.py

385 lines
10 KiB
Python

"""
Pydantic Models and Schemas
"""
from enum import Enum
from pydantic import BaseModel, ConfigDict
from typing import Optional, List
from datetime import datetime, date
class CustomerBase(BaseModel):
"""Base customer schema"""
name: str
email: Optional[str] = None
phone: Optional[str] = None
address: Optional[str] = None
class CustomerCreate(CustomerBase):
"""Schema for creating a customer"""
pass
class CustomerUpdate(BaseModel):
"""Schema for updating a customer"""
name: Optional[str] = None
email: Optional[str] = None
phone: Optional[str] = None
address: Optional[str] = None
cvr_number: Optional[str] = None
city: Optional[str] = None
postal_code: Optional[str] = None
country: Optional[str] = None
website: Optional[str] = None
mobile_phone: Optional[str] = None
invoice_email: Optional[str] = None
is_active: Optional[bool] = None
class Customer(CustomerBase):
"""Full customer schema"""
id: int
created_at: str # Changed from datetime to str for serialization
updated_at: Optional[str] = None # Changed from datetime to str for serialization
model_config = ConfigDict(from_attributes=True)
class HardwareBase(BaseModel):
"""Base hardware schema"""
serial_number: str
model: str
customer_id: int
class HardwareCreate(HardwareBase):
"""Schema for creating hardware"""
pass
class Hardware(HardwareBase):
"""Full hardware schema"""
id: int
created_at: datetime
class Config:
from_attributes = True
class VendorBase(BaseModel):
"""Base vendor schema"""
name: str
cvr_number: Optional[str] = None
domain: Optional[str] = None
email: Optional[str] = None
phone: Optional[str] = None
address: Optional[str] = None
postal_code: Optional[str] = None
city: Optional[str] = None
website: Optional[str] = None
email_pattern: Optional[str] = None
contact_person: Optional[str] = None
category: Optional[str] = None
priority: Optional[int] = 100
notes: Optional[str] = None
is_active: bool = True
class VendorCreate(VendorBase):
"""Schema for creating a vendor"""
pass
class VendorUpdate(BaseModel):
"""Schema for updating a vendor"""
name: Optional[str] = None
cvr_number: Optional[str] = None
domain: Optional[str] = None
email: Optional[str] = None
phone: Optional[str] = None
contact_person: Optional[str] = None
category: Optional[str] = None
notes: Optional[str] = None
is_active: Optional[bool] = None
class Vendor(VendorBase):
"""Full vendor schema"""
id: int
created_at: datetime
updated_at: Optional[datetime] = None
class Config:
from_attributes = True
class ConversationBase(BaseModel):
title: str
transcript: Optional[str] = None
summary: Optional[str] = None
is_private: bool = False
customer_id: Optional[int] = None
ticket_id: Optional[int] = None
category: str = "General"
class ConversationCreate(ConversationBase):
audio_file_path: str
duration_seconds: int = 0
email_message_id: Optional[int] = None
class ConversationUpdate(BaseModel):
title: Optional[str] = None
is_private: Optional[bool] = None
ticket_id: Optional[int] = None
customer_id: Optional[int] = None
category: Optional[str] = None
# For soft delete via update if needed, though usually strict API endpoint
class Conversation(ConversationBase):
id: int
audio_file_path: str
duration_seconds: int
user_id: Optional[int] = None
source: str
created_at: datetime
updated_at: Optional[datetime] = None
deleted_at: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)
class SolutionBase(BaseModel):
"""Base schema for Case Solutions"""
title: str
description: Optional[str] = None
solution_type: Optional[str] = None # Support, Drift, Konsulent, etc.
result: Optional[str] = None # Løst, Delvist, Workaround, Ej løst
class SolutionCreate(SolutionBase):
"""Schema for creating a solution"""
sag_id: int
created_by_user_id: Optional[int] = None
class SolutionUpdate(BaseModel):
"""Schema for updating a solution"""
title: Optional[str] = None
description: Optional[str] = None
solution_type: Optional[str] = None
result: Optional[str] = None
class Solution(SolutionBase):
"""Full solution schema"""
id: int
sag_id: int
created_by_user_id: Optional[int] = None
created_at: datetime
updated_at: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)
class UserAdminCreate(BaseModel):
username: str
email: str
password: str
full_name: Optional[str] = None
is_superadmin: bool = False
is_active: bool = True
group_ids: Optional[List[int]] = None
class UserGroupsUpdate(BaseModel):
group_ids: List[int]
class GroupCreate(BaseModel):
name: str
description: Optional[str] = None
class GroupPermissionsUpdate(BaseModel):
permission_ids: List[int]
class UserTwoFactorResetRequest(BaseModel):
reason: Optional[str] = None
# =====================================================
# AnyDesk Remote Support Integration Schemas
# =====================================================
class AnyDeskSessionCreate(BaseModel):
"""Schema for creating a new AnyDesk session"""
customer_id: int
contact_id: Optional[int] = None
sag_id: Optional[int] = None # Case/ticket ID
description: Optional[str] = None
created_by_user_id: Optional[int] = None
class AnyDeskSession(BaseModel):
"""Full AnyDesk session schema"""
id: int
anydesk_session_id: str
customer_id: int
contact_id: Optional[int] = None
sag_id: Optional[int] = None
session_link: Optional[str] = None
status: str # active, completed, failed, cancelled
started_at: str
ended_at: Optional[str] = None
duration_minutes: Optional[int] = None
created_by_user_id: Optional[int] = None
created_at: str
updated_at: Optional[str] = None
model_config = ConfigDict(from_attributes=True)
class AnyDeskSessionDetail(AnyDeskSession):
"""AnyDesk session with additional details"""
contact_name: Optional[str] = None
customer_name: Optional[str] = None
sag_title: Optional[str] = None
created_by_user_name: Optional[str] = None
device_info: Optional[dict] = None
metadata: Optional[dict] = None
class AnyDeskWorklogSuggestion(BaseModel):
"""Suggested worklog entry from a completed session"""
session_id: int
duration_hours: float
duration_minutes: int
description: str
start_time: str
end_time: str
billable: bool = True
work_type: str = "remote_support"
class AnyDeskSessionWithWorklog(BaseModel):
"""AnyDesk session with suggested worklog entry"""
session: AnyDeskSession
suggested_worklog: AnyDeskWorklogSuggestion
class TodoStepBase(BaseModel):
"""Base schema for case todo steps"""
title: str
description: Optional[str] = None
due_date: Optional[date] = None
class TodoStepCreate(TodoStepBase):
"""Schema for creating a todo step"""
pass
class TodoStepUpdate(BaseModel):
"""Schema for updating a todo step"""
is_done: Optional[bool] = None
class TodoStep(TodoStepBase):
"""Full todo step schema"""
id: int
sag_id: int
is_done: bool
created_by_user_id: Optional[int] = None
created_by_name: Optional[str] = None
created_at: datetime
completed_by_user_id: Optional[int] = None
completed_by_name: Optional[str] = None
completed_at: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)
class AnyDeskSessionHistory(BaseModel):
"""Session history response"""
sessions: List[AnyDeskSessionDetail]
total: int
limit: int
offset: int
class AnyDeskSessionUpdate(BaseModel):
"""Schema for updating a session (mainly status updates)"""
status: str
ended_at: Optional[str] = None
duration_minutes: Optional[int] = None
# ============================================================================
# SAG MODULE (Cases) - QuickCreate and Priority Support
# ============================================================================
class SagPriority(str, Enum):
"""Case priority levels matching database enum"""
LOW = "low"
NORMAL = "normal"
HIGH = "high"
URGENT = "urgent"
class QuickCreateAnalysis(BaseModel):
"""AI analysis result for QuickCreate feature"""
suggested_title: str
suggested_description: str
suggested_priority: SagPriority = SagPriority.NORMAL
suggested_customer_id: Optional[int] = None
suggested_customer_name: Optional[str] = None
suggested_technician_id: Optional[int] = None
suggested_technician_name: Optional[str] = None
suggested_group_id: Optional[int] = None
suggested_group_name: Optional[str] = None
suggested_tags: List[str] = []
hardware_references: List[dict] = [] # [{id, brand, model, serial_number}]
confidence: float = 0.0
ai_reasoning: Optional[str] = None # Debug info for low confidence
model_config = ConfigDict(from_attributes=True)
class SagBase(BaseModel):
"""Base schema for SAG (cases)"""
titel: str
beskrivelse: Optional[str] = None
priority: SagPriority = SagPriority.NORMAL
customer_id: Optional[int] = None
ansvarlig_bruger_id: Optional[int] = None
assigned_group_id: Optional[int] = None
deadline: Optional[datetime] = None
class SagCreate(SagBase):
"""Schema for creating a case"""
template_key: Optional[str] = None
tags: Optional[List[str]] = None
class SagUpdate(BaseModel):
"""Schema for updating a case"""
titel: Optional[str] = None
beskrivelse: Optional[str] = None
priority: Optional[SagPriority] = None
status: Optional[str] = None
ansvarlig_bruger_id: Optional[int] = None
assigned_group_id: Optional[int] = None
deadline: Optional[datetime] = None
class Sag(SagBase):
"""Full case schema"""
id: int
status: str
template_key: Optional[str] = None
created_by_user_id: int
created_at: datetime
updated_at: datetime
deleted_at: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)