Files
gw-svelte/mail-api/mail_api/models.py
T

188 lines
4.9 KiB
Python
Raw Normal View History

2026-05-19 23:36:58 +12:00
"""Pydantic request/response models for the mail API."""
from __future__ import annotations
2026-05-26 08:30:08 +12:00
from typing import Any, Literal
2026-05-19 23:36:58 +12:00
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
2026-06-17 21:51:29 +12:00
vetAddress: str
2026-05-19 23:36:58 +12:00
vetPhone: str
emergencyContactName: str
emergencyContactPhone: str
2026-06-17 21:51:29 +12:00
regularFleaTickTreatment: str = ""
petInsurance: str = ""
petInsuranceOwnerExpenseAccepted: bool = False
2026-05-19 23:36:58 +12:00
councilRegistrationConfirmed: bool = False
vaccinationsConfirmed: bool = False
emergencyVetConsent: bool = False
termsAccepted: bool = False
signatureDataUrl: str
submissionSnapshot: dict[str, Any] = {}
class WelcomePackEmailRequest(BaseModel):
email: EmailStr
2026-06-17 21:51:29 +12:00
# Owner-set subject line. Defaults to "Goodwalk Onboarding - <Dog Name>" when
# blank (resolved server-side so scheduled sends keep a sensible subject too).
subject: str = ""
2026-05-19 23:36:58 +12:00
serviceType: str
priceDetails: str
startDate: str
preview: bool = False
2026-06-17 21:51:29 +12:00
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
2026-05-19 23:36:58 +12:00
class BirthdayEmailRequest(BaseModel):
email: EmailStr
preview: bool = False
2026-06-17 21:51:29 +12:00
previewRecipients: list[EmailStr] = []
2026-05-19 23:36:58 +12:00
class BirthdayAutoSendRequest(BaseModel):
email: EmailStr
enabled: bool
2026-05-26 08:30:08 +12:00
# 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 = ""
2026-06-17 21:51:29 +12:00
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
2026-05-19 23:36:58 +12:00
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
2026-06-17 21:51:29 +12:00
previewRecipients: list[EmailStr] = []