Add frontend/modules/loyalty with types, API client, design system, feature pages and thin App Router routes under app/loyalty/. BFF proxy at app/api/loyalty/. Include loyalty frontend docs. Co-authored-by: Cursor <cursoragent@cursor.com>
302 lines
8.6 KiB
Python
302 lines
8.6 KiB
Python
"""Beauty Business foundation DTOs — Phase 14.0."""
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from uuid import UUID
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
|
|
from app.models.types import (
|
|
BusinessFormat,
|
|
LifecycleStatus,
|
|
ProviderKind,
|
|
ProviderStatus,
|
|
BookingEngineStatus,
|
|
)
|
|
from app.schemas.common import ORMBase
|
|
|
|
_FORBID = ConfigDict(extra="forbid")
|
|
|
|
|
|
class BeautyOrganizationCreate(BaseModel):
|
|
model_config = _FORBID
|
|
|
|
code: str = Field(max_length=50)
|
|
name: str = Field(max_length=255)
|
|
description: str | None = None
|
|
status: LifecycleStatus = LifecycleStatus.DRAFT
|
|
business_format: BusinessFormat = BusinessFormat.SALON
|
|
legal_name: str | None = Field(default=None, max_length=255)
|
|
timezone: str = Field(default="Asia/Tehran", max_length=64)
|
|
language: str = Field(default="fa", max_length=16)
|
|
currency_code: str = Field(default="IRR", max_length=3)
|
|
settings: dict | None = None
|
|
|
|
|
|
class BeautyOrganizationUpdate(BaseModel):
|
|
model_config = _FORBID
|
|
|
|
name: str | None = Field(default=None, max_length=255)
|
|
description: str | None = None
|
|
status: LifecycleStatus | None = None
|
|
business_format: BusinessFormat | None = None
|
|
legal_name: str | None = Field(default=None, max_length=255)
|
|
timezone: str | None = Field(default=None, max_length=64)
|
|
language: str | None = Field(default=None, max_length=16)
|
|
currency_code: str | None = Field(default=None, max_length=3)
|
|
settings: dict | None = None
|
|
version: int = Field(ge=1)
|
|
|
|
|
|
class BeautyOrganizationRead(ORMBase):
|
|
id: UUID
|
|
tenant_id: UUID
|
|
code: str
|
|
name: str
|
|
description: str | None
|
|
status: LifecycleStatus
|
|
business_format: BusinessFormat
|
|
legal_name: str | None
|
|
timezone: str
|
|
language: str
|
|
currency_code: str
|
|
settings: dict | None
|
|
version: int
|
|
is_deleted: bool
|
|
created_by: str | None
|
|
updated_by: str | None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class BeautyBranchCreate(BaseModel):
|
|
model_config = _FORBID
|
|
|
|
organization_id: UUID
|
|
code: str = Field(max_length=50)
|
|
name: str = Field(max_length=255)
|
|
description: str | None = None
|
|
status: LifecycleStatus = LifecycleStatus.ACTIVE
|
|
business_format: BusinessFormat | None = None
|
|
address: dict | None = None
|
|
timezone: str | None = Field(default=None, max_length=64)
|
|
working_hours: dict | None = None
|
|
metadata_json: dict | None = None
|
|
|
|
|
|
class BeautyBranchUpdate(BaseModel):
|
|
model_config = _FORBID
|
|
|
|
name: str | None = Field(default=None, max_length=255)
|
|
description: str | None = None
|
|
status: LifecycleStatus | None = None
|
|
business_format: BusinessFormat | None = None
|
|
address: dict | None = None
|
|
timezone: str | None = Field(default=None, max_length=64)
|
|
working_hours: dict | None = None
|
|
metadata_json: dict | None = None
|
|
|
|
|
|
class BeautyBranchRead(ORMBase):
|
|
id: UUID
|
|
tenant_id: UUID
|
|
organization_id: UUID
|
|
code: str
|
|
name: str
|
|
description: str | None
|
|
status: LifecycleStatus
|
|
business_format: BusinessFormat | None
|
|
address: dict | None
|
|
timezone: str | None
|
|
working_hours: dict | None
|
|
metadata_json: dict | None
|
|
is_deleted: bool
|
|
created_by: str | None
|
|
updated_by: str | None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class ExternalProviderConfigCreate(BaseModel):
|
|
model_config = _FORBID
|
|
|
|
organization_id: UUID | None = None
|
|
code: str = Field(max_length=50)
|
|
name: str = Field(max_length=255)
|
|
provider_kind: ProviderKind = ProviderKind.CUSTOM
|
|
adapter_key: str = Field(max_length=100)
|
|
status: ProviderStatus = ProviderStatus.REGISTERED
|
|
priority: int = Field(default=100, ge=0)
|
|
credentials_ref: str | None = Field(default=None, max_length=255)
|
|
config: dict | None = None
|
|
capabilities: dict | None = None
|
|
|
|
|
|
class ExternalProviderConfigUpdate(BaseModel):
|
|
model_config = _FORBID
|
|
|
|
name: str | None = Field(default=None, max_length=255)
|
|
provider_kind: ProviderKind | None = None
|
|
adapter_key: str | None = Field(default=None, max_length=100)
|
|
status: ProviderStatus | None = None
|
|
priority: int | None = Field(default=None, ge=0)
|
|
credentials_ref: str | None = Field(default=None, max_length=255)
|
|
config: dict | None = None
|
|
capabilities: dict | None = None
|
|
version: int = Field(ge=1)
|
|
|
|
|
|
class ExternalProviderConfigRead(ORMBase):
|
|
id: UUID
|
|
tenant_id: UUID
|
|
organization_id: UUID | None
|
|
code: str
|
|
name: str
|
|
provider_kind: ProviderKind
|
|
adapter_key: str
|
|
status: ProviderStatus
|
|
priority: int
|
|
credentials_ref: str | None
|
|
config: dict | None
|
|
capabilities: dict | None
|
|
version: int
|
|
is_deleted: bool
|
|
created_by: str | None
|
|
updated_by: str | None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class BookingEngineRegistrationCreate(BaseModel):
|
|
model_config = _FORBID
|
|
|
|
organization_id: UUID | None = None
|
|
code: str = Field(max_length=50)
|
|
name: str = Field(max_length=255)
|
|
adapter_key: str = Field(max_length=100)
|
|
status: BookingEngineStatus = BookingEngineStatus.REGISTERED
|
|
is_default: bool = False
|
|
config: dict | None = None
|
|
capabilities: dict | None = None
|
|
|
|
|
|
class BookingEngineRegistrationUpdate(BaseModel):
|
|
model_config = _FORBID
|
|
|
|
name: str | None = Field(default=None, max_length=255)
|
|
adapter_key: str | None = Field(default=None, max_length=100)
|
|
status: BookingEngineStatus | None = None
|
|
is_default: bool | None = None
|
|
config: dict | None = None
|
|
capabilities: dict | None = None
|
|
version: int = Field(ge=1)
|
|
|
|
|
|
class BookingEngineRegistrationRead(ORMBase):
|
|
id: UUID
|
|
tenant_id: UUID
|
|
organization_id: UUID | None
|
|
code: str
|
|
name: str
|
|
adapter_key: str
|
|
status: BookingEngineStatus
|
|
is_default: bool
|
|
config: dict | None
|
|
capabilities: dict | None
|
|
version: int
|
|
is_deleted: bool
|
|
created_by: str | None
|
|
updated_by: str | None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class BeautyConfigurationCreate(BaseModel):
|
|
model_config = _FORBID
|
|
|
|
organization_id: UUID
|
|
branch_id: UUID | None = None
|
|
code: str = Field(max_length=50)
|
|
working_hours: dict | None = None
|
|
booking_policies: dict | None = None
|
|
cancellation_policies: dict | None = None
|
|
reminder_policies: dict | None = None
|
|
custom_fields: dict | None = None
|
|
timezone: str = Field(default="Asia/Tehran", max_length=64)
|
|
language: str = Field(default="fa", max_length=16)
|
|
currency_code: str = Field(default="IRR", max_length=3)
|
|
|
|
|
|
class BeautyConfigurationUpdate(BaseModel):
|
|
model_config = _FORBID
|
|
|
|
branch_id: UUID | None = None
|
|
working_hours: dict | None = None
|
|
booking_policies: dict | None = None
|
|
cancellation_policies: dict | None = None
|
|
reminder_policies: dict | None = None
|
|
custom_fields: dict | None = None
|
|
timezone: str | None = Field(default=None, max_length=64)
|
|
language: str | None = Field(default=None, max_length=16)
|
|
currency_code: str | None = Field(default=None, max_length=3)
|
|
version: int = Field(ge=1)
|
|
|
|
|
|
class BeautyConfigurationRead(ORMBase):
|
|
id: UUID
|
|
tenant_id: UUID
|
|
organization_id: UUID
|
|
branch_id: UUID | None
|
|
code: str
|
|
working_hours: dict | None
|
|
booking_policies: dict | None
|
|
cancellation_policies: dict | None
|
|
reminder_policies: dict | None
|
|
custom_fields: dict | None
|
|
timezone: str
|
|
language: str
|
|
currency_code: str
|
|
version: int
|
|
is_deleted: bool
|
|
created_by: str | None
|
|
updated_by: str | None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class BeautySettingUpsert(BaseModel):
|
|
model_config = _FORBID
|
|
|
|
organization_id: UUID | None = None
|
|
branch_id: UUID | None = None
|
|
key: str = Field(max_length=100)
|
|
value: dict | None = None
|
|
description: str | None = None
|
|
|
|
|
|
class BeautySettingRead(ORMBase):
|
|
id: UUID
|
|
tenant_id: UUID
|
|
organization_id: UUID | None
|
|
branch_id: UUID | None
|
|
key: str
|
|
value: dict | None
|
|
description: str | None
|
|
is_deleted: bool
|
|
created_by: str | None
|
|
updated_by: str | None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class BeautyAuditLogRead(ORMBase):
|
|
id: UUID
|
|
tenant_id: UUID
|
|
entity_type: str
|
|
entity_id: UUID
|
|
action: str
|
|
actor_user_id: str | None
|
|
changes: dict | None
|
|
message: str | None
|
|
created_at: datetime
|