TorbatYar/backend/services/communication/app/schemas/common.py
Mortezakoohjani e41ecfad4c Sync platform docs, infra, and module services with Accounting integration.
Include Loyalty/Communication/Sports Center backends and registry updates alongside production nginx and compose wiring.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-25 22:35:23 +03:30

312 lines
7.6 KiB
Python

"""Pydantic schemas for Communication APIs."""
from __future__ import annotations
from datetime import datetime
from decimal import Decimal
from typing import Any
from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field
class ORMModel(BaseModel):
model_config = ConfigDict(from_attributes=True)
class ProviderCreate(BaseModel):
name: str
provider_kind: str
channel: str
priority: int = 100
credentials: dict[str, Any] | None = None
settings: dict[str, Any] | None = None
balance: Decimal | None = None
rate_limit_per_minute: int | None = None
max_retries: int = 3
is_default: bool = False
class ProviderUpdate(BaseModel):
name: str | None = None
priority: int | None = None
credentials: dict[str, Any] | None = None
settings: dict[str, Any] | None = None
balance: Decimal | None = None
rate_limit_per_minute: int | None = None
max_retries: int | None = None
status: str | None = None
is_default: bool | None = None
class ProviderOut(ORMModel):
id: UUID
tenant_id: UUID
name: str
provider_kind: str
channel: str
status: str
priority: int
balance: Decimal | None = None
rate_limit_per_minute: int | None = None
max_retries: int
circuit_state: str
consecutive_failures: int
last_health_at: datetime | None = None
last_error: str | None = None
is_default: bool
created_at: datetime
updated_at: datetime
class SenderCreate(BaseModel):
channel: str
value: str
label: str | None = None
provider_config_id: UUID | None = None
is_default: bool = False
is_active: bool = True
class SenderOut(ORMModel):
id: UUID
tenant_id: UUID
channel: str
value: str
label: str | None = None
provider_config_id: UUID | None = None
is_default: bool
is_active: bool
created_at: datetime
class TemplateCreate(BaseModel):
template_key: str
name: str
channel: str
locale: str = "fa"
body: str
subject: str | None = None
variables: list[str] | None = None
class TemplateOut(ORMModel):
id: UUID
tenant_id: UUID
template_key: str
name: str
channel: str
locale: str
version: int
status: str
body: str
subject: str | None = None
variables: list[str] | None = None
approved_by: str | None = None
approved_at: datetime | None = None
rejection_reason: str | None = None
created_at: datetime
class TemplatePreviewRequest(BaseModel):
variables: dict[str, Any] = Field(default_factory=dict)
class TemplatePreviewResponse(BaseModel):
rendered: str
subject: str | None = None
class ContactCreate(BaseModel):
display_name: str | None = None
phone: str | None = None
email: str | None = None
push_token: str | None = None
metadata_json: dict[str, Any] | None = None
tags: list[str] | None = None
class ContactOut(ORMModel):
id: UUID
tenant_id: UUID
display_name: str | None = None
phone: str | None = None
email: str | None = None
push_token: str | None = None
metadata_json: dict[str, Any] | None = None
tags: list[str] | None = None
created_at: datetime
class ContactSourceCreate(BaseModel):
name: str
source_type: str
base_url: str | None = None
endpoint_path: str | None = None
auth_config: dict[str, Any] | None = None
query_mapping: dict[str, Any] | None = None
field_mapping: dict[str, Any] | None = None
is_active: bool = True
class ContactSourceOut(ORMModel):
id: UUID
tenant_id: UUID
name: str
source_type: str
base_url: str | None = None
endpoint_path: str | None = None
field_mapping: dict[str, Any] | None = None
is_active: bool
created_at: datetime
class MessageSendRequest(BaseModel):
channel: str = "sms"
to_address: str | None = None
from_address: str | None = None
body: str | None = None
subject: str | None = None
template_key: str | None = None
template_id: UUID | None = None
template_variables: dict[str, Any] | None = None
priority: str = "normal"
scheduled_at: datetime | None = None
correlation_id: str | None = None
source_module: str | None = None
metadata_json: dict[str, Any] | None = None
contact_source_id: UUID | None = None
contact_query: dict[str, Any] | None = None
batch: bool = False
process_immediately: bool = True
class MessageOut(ORMModel):
id: UUID
tenant_id: UUID
channel: str
status: str
to_address: str
from_address: str | None = None
subject: str | None = None
body: str
template_key: str | None = None
provider_config_id: UUID | None = None
provider_message_id: str | None = None
priority: str
scheduled_at: datetime | None = None
sent_at: datetime | None = None
delivered_at: datetime | None = None
failed_at: datetime | None = None
error_code: str | None = None
error_message: str | None = None
retry_count: int
correlation_id: str | None = None
source_module: str | None = None
created_at: datetime
class DeliveryEventOut(ORMModel):
id: UUID
message_id: UUID
status: str
provider_config_id: UUID | None = None
detail: str | None = None
payload: dict[str, Any] | None = None
created_at: datetime
class QueueItemOut(ORMModel):
id: UUID
message_id: UUID
status: str
priority: str
attempt: int
max_attempts: int
available_at: datetime
is_dead_letter: bool
last_error: str | None = None
batch_id: str | None = None
created_at: datetime
class OTPRequest(BaseModel):
destination: str
channel: str = "sms"
purpose: str | None = None
ttl_seconds: int | None = None
code_length: int = 6
class OTPRequestOut(BaseModel):
challenge_id: UUID
destination: str
channel: str
expires_at: datetime
message_id: UUID | None = None
# Returned only in non-production for tests/dev
debug_code: str | None = None
class OTPVerifyRequest(BaseModel):
destination: str
code: str
challenge_id: UUID | None = None
class OTPVerifyOut(BaseModel):
verified: bool
challenge_id: UUID | None = None
status: str
class WebhookIn(BaseModel):
provider_kind: str
event_type: str
external_id: str | None = None
message_id: UUID | None = None
payload: dict[str, Any] | None = None
signature: str | None = None
class WebhookOut(ORMModel):
id: UUID
provider_kind: str
event_type: str
external_id: str | None = None
message_id: UUID | None = None
signature_valid: bool
processed: bool
created_at: datetime
class CapabilitiesOut(BaseModel):
service: str
version: str
channels: list[dict[str, Any]]
features: list[str]
independent: bool = True
requires_other_modules: bool = False
class ProviderStatusOut(BaseModel):
id: UUID
name: str
provider_kind: str
channel: str
status: str
circuit_state: str
consecutive_failures: int
balance: Decimal | None = None
rate_limit_per_minute: int | None = None
last_health_at: datetime | None = None
last_error: str | None = None
healthy: bool
class MonitoringStatsOut(BaseModel):
messages_by_status: dict[str, int]
queue_by_status: dict[str, int]
providers: list[ProviderStatusOut]
rate_limit_deferrals: int = 0
checked_at: str | None = None