feat(backend): Fix client-profile endpoint and add attachment support

- Fixed client-profile GET endpoint to prevent 500 errors
- Made ClientProfileResponse fields optional (id, created_at, updated_at)
- Returns empty profile data instead of creating DB entry on GET
- Added new attachment model and schemas for file handling
- Added file handler core utility for upload management
This commit is contained in:
2026-02-09 13:27:45 -07:00
parent ea682d8cd9
commit d4ff32dac7
5 changed files with 234 additions and 8 deletions

View File

@@ -0,0 +1,25 @@
"""
Attachment Schemas - ServiceManagerWeb
"""
from pydantic import BaseModel, ConfigDict, Field
from datetime import datetime
from typing import Optional
import uuid
class AttachmentResponse(BaseModel):
"""Schema para respuesta de attachment"""
id: uuid.UUID
ticket_id: uuid.UUID
comment_id: Optional[uuid.UUID] = None
uploaded_by: uuid.UUID
filename: str
original_filename: str
mime_type: str
file_size: int
file_path: str
uploaded_by_name: Optional[str] = None
created_at: datetime
download_url: Optional[str] = None
model_config = ConfigDict(from_attributes=True)

View File

@@ -133,10 +133,10 @@ class ClientProfileUpdate(ClientProfileBase):
class ClientProfileResponse(ClientProfileBase):
"""Schema de respuesta para ClientProfile."""
id: uuid.UUID
id: Optional[uuid.UUID] = None
tenant_id: uuid.UUID
created_at: datetime
updated_at: datetime
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
class Config:
from_attributes = True

View File

@@ -50,11 +50,49 @@ async def get_current_client_profile(
profile = result.scalar_one_or_none()
if not profile:
# Si no existe, crear uno vacío
profile = ClientProfile(tenant_id=current_tenant.id)
db.add(profile)
await db.commit()
await db.refresh(profile)
# Si no existe, devolver un perfil vacío con solo tenant_id
# No crear en base de datos hasta que el usuario guarde
return ClientProfileResponse(
id=None,
tenant_id=current_tenant.id,
business_name=None,
commercial_name=None,
client_code=None,
client_type=None,
rfc=None,
tax_id=None,
country=None,
state=None,
city=None,
address=None,
external_number=None,
internal_number=None,
postal_code=None,
neighborhood=None,
main_phone=None,
secondary_phone=None,
direct_phone=None,
phone_extension=None,
fax=None,
business_hours=None,
website=None,
main_email=None,
billing_email=None,
advertising_medium=None,
nationality=None,
logo_url=None,
company_representative=None,
legal_representative=None,
credit_limit=None,
payment_terms=None,
preferred_currency="MXN",
send_to_billing=False,
is_active_client=True,
is_prospect=False,
notes=None,
created_at=None,
updated_at=None
)
return profile