Files
ponzischeme89 6d44e05de4 v1
2026-04-18 07:23:55 +12:00

371 lines
11 KiB
Python

import uuid
from datetime import datetime
from typing import Optional, Any
from pydantic import BaseModel
# ── Magic link ─────────────────────────────────────────────────────────────────
class MagicLinkVerifySchema(BaseModel):
token: str
# ── Claim ──────────────────────────────────────────────────────────────────────
class ClaimRequestSchema(BaseModel):
email: str
class ClaimCompleteSchema(BaseModel):
email: str
code: str
password: str
class MemberClaimVerifyCodeSchema(BaseModel):
code: str
password: str
# ── Auth ───────────────────────────────────────────────────────────────────────
class MemberLoginSchema(BaseModel):
email: str
password: str
class MemberLoginVerifySchema(BaseModel):
email: str
code: str
class MemberTokenResponse(BaseModel):
access_token: str
refresh_token: str
token_type: str = "bearer"
class MemberRefreshSchema(BaseModel):
refresh_token: str
class MemberLogoutSchema(BaseModel):
refresh_token: Optional[str] = None
# ── Profile ────────────────────────────────────────────────────────────────────
class MemberProfileResponse(BaseModel):
id: uuid.UUID
email: str
first_name: str
last_name: str
phone: Optional[str]
address: Optional[str]
emergency_contact: Optional[str]
notifications_enabled: bool
is_claimed: bool
member_status: str
activated_at: Optional[datetime]
created_at: datetime
model_config = {"from_attributes": True}
class MemberProfileUpdate(BaseModel):
first_name: Optional[str] = None
last_name: Optional[str] = None
phone: Optional[str] = None
address: Optional[str] = None
emergency_contact: Optional[str] = None
notifications_enabled: Optional[bool] = None
class MemberOnboardingResponse(BaseModel):
id: uuid.UUID
email: str
first_name: str
last_name: str
phone: Optional[str]
address: Optional[str]
emergency_contact: Optional[str]
notifications_enabled: bool
onboarding_data: Optional[Any]
is_claimed: bool
member_status: str
claimed_at: Optional[datetime]
onboarding_completed_at: Optional[datetime]
contract_signed_at: Optional[datetime]
contract_signer_name: Optional[str]
contract_version: Optional[str]
activated_at: Optional[datetime]
created_at: datetime
model_config = {"from_attributes": True}
class MemberOnboardingUpdate(BaseModel):
first_name: Optional[str] = None
last_name: Optional[str] = None
phone: Optional[str] = None
address: Optional[str] = None
emergency_contact: Optional[str] = None
onboarding_data: Optional[Any] = None
complete_onboarding: bool = False
class ContractSignSchema(BaseModel):
signer_name: str
agreed: bool
contract_version: Optional[str] = None
# ── Walks ──────────────────────────────────────────────────────────────────────
class WalkResponse(BaseModel):
id: uuid.UUID
service_type: str
walked_at: datetime
duration_minutes: int
notes: Optional[str]
recorded_by: Optional[str]
created_at: datetime
model_config = {"from_attributes": True}
# ── Bookings ───────────────────────────────────────────────────────────────────
class BookingCreate(BaseModel):
service_type: str
requested_day: Optional[str] = None
requested_date: Optional[datetime] = None
requested_timeslot: Optional[str] = None
notes: Optional[str] = None
class BookingResponse(BaseModel):
id: uuid.UUID
service_type: str
requested_date: Optional[datetime]
status: str
notes: Optional[str]
admin_notes: Optional[str]
created_at: datetime
model_config = {"from_attributes": True}
class BookingSlotAvailabilityResponse(BaseModel):
slot: str
label: str
booked: int
capacity: int
remaining: int
is_available: bool
class BookingAvailabilityDayResponse(BaseModel):
date: str
label: str
slots: list[BookingSlotAvailabilityResponse]
class BookingAvailabilityResponse(BaseModel):
requested_date: str
selected: BookingAvailabilityDayResponse
alternatives: list[BookingAvailabilityDayResponse]
# ── Messages ───────────────────────────────────────────────────────────────────
class MessageResponse(BaseModel):
id: uuid.UUID
subject: str
body: str
sent_by: Optional[str]
read_at: Optional[datetime]
created_at: datetime
direction: str = "inbound"
reply_to_id: Optional[uuid.UUID] = None
model_config = {"from_attributes": True}
class MemberReplySchema(BaseModel):
body: str
# ── Admin: Create Member ───────────────────────────────────────────────────────
class AdminCreateMember(BaseModel):
email: str
first_name: str
last_name: str
phone: Optional[str] = None
address: Optional[str] = None
emergency_contact: Optional[str] = None
onboarding_data: Optional[Any] = None
service_pricing_overrides: Optional[Any] = None
force_two_factor: Optional[bool] = None
class AdminMemberResponse(BaseModel):
id: uuid.UUID
email: str
first_name: str
last_name: str
phone: Optional[str]
address: Optional[str]
emergency_contact: Optional[str]
notifications_enabled: bool
onboarding_data: Optional[Any]
is_claimed: bool
is_active: bool
member_status: str
claimed_at: Optional[datetime]
onboarding_completed_at: Optional[datetime]
contract_signed_at: Optional[datetime]
contract_signer_name: Optional[str]
contract_version: Optional[str]
activated_at: Optional[datetime]
service_pricing_overrides: Optional[Any]
force_two_factor: Optional[bool]
created_at: datetime
model_config = {"from_attributes": True}
class AdminMemberUpdate(BaseModel):
first_name: Optional[str] = None
last_name: Optional[str] = None
phone: Optional[str] = None
address: Optional[str] = None
emergency_contact: Optional[str] = None
notifications_enabled: Optional[bool] = None
onboarding_data: Optional[Any] = None
is_active: Optional[bool] = None
member_status: Optional[str] = None
service_pricing_overrides: Optional[Any] = None
force_two_factor: Optional[bool] = None
class AdminMemberToggleAction(BaseModel):
enabled: bool
class AdminBookingResponse(BaseModel):
id: uuid.UUID
member_id: uuid.UUID
service_type: str
requested_date: Optional[datetime]
status: str
notes: Optional[str]
admin_notes: Optional[str]
created_at: datetime
# Joined fields
member_first_name: Optional[str] = None
member_last_name: Optional[str] = None
member_email: Optional[str] = None
member_dog_name: Optional[str] = None
member_dog_breed: Optional[str] = None
model_config = {"from_attributes": True}
class AdminBookingCreate(BaseModel):
member_id: uuid.UUID
service_type: str
requested_date: Optional[datetime] = None
status: str = "confirmed"
notes: Optional[str] = None
admin_notes: Optional[str] = None
class AdminBookingUpdate(BaseModel):
requested_date: Optional[datetime] = None
status: Optional[str] = None # pending | confirmed | cancelled | completed
notes: Optional[str] = None
admin_notes: Optional[str] = None
# ── Admin: Record Walk ─────────────────────────────────────────────────────────
class AdminRecordWalk(BaseModel):
member_id: uuid.UUID
walked_at: datetime
service_type: str
duration_minutes: int = 60
notes: Optional[str] = None
# ── Admin: Send Message ────────────────────────────────────────────────────────
class AdminSendMessage(BaseModel):
member_id: uuid.UUID
subject: str
body: str
class AdminNotificationSettingsResponse(BaseModel):
automatic_member_notifications_enabled: bool
nz_public_holiday_notifications_enabled: bool
invoice_reminder_notifications_enabled: bool
invoice_day_of_week: int
class AdminNotificationSettingsUpdate(BaseModel):
automatic_member_notifications_enabled: Optional[bool] = None
nz_public_holiday_notifications_enabled: Optional[bool] = None
invoice_reminder_notifications_enabled: Optional[bool] = None
invoice_day_of_week: Optional[int] = None
class AdminNotificationRunResponse(BaseModel):
automatic_member_notifications_enabled: bool
public_holiday_messages_sent: int
invoice_reminders_sent: int
class AdminNotificationFeedItemResponse(BaseModel):
id: str
type: str
title: str
description: str
created_at: datetime
href: str
class AdminNotificationsResponse(BaseModel):
items: list[AdminNotificationFeedItemResponse]
total: int
settings: AdminNotificationSettingsResponse
class AdminMessageHistoryResponse(BaseModel):
id: uuid.UUID
member_id: uuid.UUID
member_name: str
member_email: str
subject: str
body: str
sent_by: Optional[str]
created_at: datetime
read_at: Optional[datetime]
# ── Contract ───────────────────────────────────────────────────────────────────
class ContractResponse(BaseModel):
onboarding_data: Optional[Any]
member_name: str
email: str
member_status: str
contract_signed_at: Optional[datetime]
contract_signer_name: Optional[str]
contract_version: Optional[str]
activated_at: Optional[datetime]
joined_at: datetime
model_config = {"from_attributes": True}