"""Pydantic request/response models for the mail API.""" from __future__ import annotations from typing import Any, Literal from pydantic import BaseModel, EmailStr class BaseSubmission(BaseModel): fullName: str email: EmailStr phone: str website: str = "" formStartedAt: int | None = None visitStartedAt: int | None = None pageEnteredAt: int | None = None firstInteractionAt: int | None = None sendClickedAt: int | None = None referrer: str = "" page: str = "" class BookingSubmission(BaseSubmission): enquiryType: str = "booking" petName: str = "" location: str = "" message: str = "" services: list[str] = [] stepChanges: int = 0 journey: list[str] = [] class OnboardingSubmission(BaseSubmission): address: str dogName: str dogBreed: str dogAge: str = "" servicesNeeded: list[str] = [] temperament: str = "" medicalNotes: str = "" accessInstructions: str = "" vetName: str vetAddress: str vetPhone: str emergencyContactName: str emergencyContactPhone: str regularFleaTickTreatment: str = "" petInsurance: str = "" petInsuranceOwnerExpenseAccepted: bool = False councilRegistrationConfirmed: bool = False vaccinationsConfirmed: bool = False emergencyVetConsent: bool = False termsAccepted: bool = False signatureDataUrl: str submissionSnapshot: dict[str, Any] = {} class WelcomePackEmailRequest(BaseModel): email: EmailStr # Owner-set subject line. Defaults to "Goodwalk Onboarding - " when # blank (resolved server-side so scheduled sends keep a sensible subject too). subject: str = "" serviceType: str priceDetails: str startDate: str preview: bool = False previewRecipients: list[EmailStr] = [] # ISO 8601 local datetime (e.g. "2026-06-20T14:30"). When set on a non-preview # request, the welcome email is queued for reliable delivery at that time # instead of being sent immediately. scheduledFor: str | None = None class ScheduledEmailCancelRequest(BaseModel): id: str class ScheduledEmailRescheduleRequest(BaseModel): id: str scheduledFor: str class BirthdayEmailRequest(BaseModel): email: EmailStr preview: bool = False previewRecipients: list[EmailStr] = [] class BirthdayAutoSendRequest(BaseModel): email: EmailStr enabled: bool # Client lifecycle status. Soft-delete only — every client stays on file so the # history is preserved for future newsletter / retention work. ClientLifecycleStatus = Literal["active", "paused", "cancelled", "archived"] class ClientStatusUpdate(BaseModel): email: EmailStr status: ClientLifecycleStatus reason: str = "" class ClientProfileUpdate(BaseModel): email: EmailStr nextEmail: EmailStr fullName: str phone: str = "" address: str = "" dogName: str class ResetOnboardingRequest(BaseModel): """Owner-initiated reset: keep the client's saved details but mark their onboarding incomplete so they can sign in and complete the new form (used for clients imported from the legacy Gravity Forms data).""" email: EmailStr class NewClientRequest(BaseModel): """Owner-initiated client creation (e.g. leads from Instagram / Facebook that never came through the public enquiry form). Registers the email so the client can access the onboarding form, and seeds a profile.""" email: EmailStr fullName: str phone: str = "" address: str = "" dogName: str = "" dogBreed: str = "" # Where the client came from, e.g. "Instagram", "Facebook", "Referral". source: str = "" # When true (and the MYOB integration is configured), also create the client # as a customer contact in MYOB. Non-fatal: a MYOB failure never blocks the # local client from being created. createInMyob: bool = False class ContractSubmission(BaseSubmission): address: str dogName: str dogBreed: str dogAge: str = "" serviceType: str startDate: str walkFrequency: str = "" additionalNotes: str = "" agreeServiceTerms: bool = False agreeCancellation: bool = False agreePayment: bool = False agreeEmergency: bool = False agreeLiability: bool = False agreeAccuracy: bool = False signatureDataUrl: str class RenderMessageRequest(BaseModel): templateId: str heading: str = "" body: str = "" ctaLabel: str = "" ctaUrl: str = "" subHeading: str = "" highlightText: str = "" signOff: str = "" footerNote: str = "" fontId: str = "system" class SendMessageRequest(BaseModel): templateId: str subject: str heading: str = "" body: str = "" ctaLabel: str = "" ctaUrl: str = "" subHeading: str = "" highlightText: str = "" signOff: str = "" footerNote: str = "" fontId: str = "system" recipients: list[EmailStr] = [] preview: bool = False previewRecipients: list[EmailStr] = []