238 lines
5.8 KiB
Rust
238 lines
5.8 KiB
Rust
use cot::db::{Auto, ForeignKey, model};
|
|
|
|
/// Lead status: new request from the website
|
|
/// new -> in_progress -> converted | rejected
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub enum LeadStatus {
|
|
New,
|
|
InProgress,
|
|
Converted,
|
|
Rejected,
|
|
}
|
|
|
|
impl LeadStatus {
|
|
pub fn as_str(&self) -> &'static str {
|
|
match self {
|
|
Self::New => "new",
|
|
Self::InProgress => "in_progress",
|
|
Self::Converted => "converted",
|
|
Self::Rejected => "rejected",
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Client status
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub enum ClientStatus {
|
|
Active,
|
|
Archived,
|
|
}
|
|
|
|
impl ClientStatus {
|
|
pub fn as_str(&self) -> &'static str {
|
|
match self {
|
|
Self::Active => "active",
|
|
Self::Archived => "archived",
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Visit status
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub enum VisitStatus {
|
|
Scheduled,
|
|
Completed,
|
|
Cancelled,
|
|
Deleted,
|
|
}
|
|
|
|
impl VisitStatus {
|
|
pub fn as_str(&self) -> &'static str {
|
|
match self {
|
|
Self::Scheduled => "scheduled",
|
|
Self::Completed => "completed",
|
|
Self::Cancelled => "cancelled",
|
|
Self::Deleted => "deleted",
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Media file type
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub enum MediaType {
|
|
Photo,
|
|
Video,
|
|
}
|
|
|
|
impl MediaType {
|
|
pub fn as_str(&self) -> &'static str {
|
|
match self {
|
|
Self::Photo => "photo",
|
|
Self::Video => "video",
|
|
}
|
|
}
|
|
}
|
|
|
|
/// User (admin) status
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub enum UserStatus {
|
|
Active,
|
|
Archived,
|
|
}
|
|
|
|
impl UserStatus {
|
|
pub fn as_str(&self) -> &'static str {
|
|
match self {
|
|
Self::Active => "active",
|
|
Self::Archived => "archived",
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Models
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/// A lead submitted via the public website form.
|
|
#[derive(Debug, Clone)]
|
|
#[model]
|
|
pub struct Lead {
|
|
#[model(primary_key)]
|
|
pub id: Auto<i64>,
|
|
pub name: String,
|
|
pub phone: Option<String>,
|
|
pub email: Option<String>,
|
|
pub comment: Option<String>,
|
|
/// new | in_progress | converted | rejected
|
|
pub status: String,
|
|
pub client_id: Option<ForeignKey<Client>>,
|
|
pub created_at: chrono::NaiveDateTime,
|
|
pub updated_at: chrono::NaiveDateTime,
|
|
}
|
|
|
|
/// A confirmed client created from a lead (or manually).
|
|
#[derive(Debug, Clone)]
|
|
#[model]
|
|
pub struct Client {
|
|
#[model(primary_key)]
|
|
pub id: Auto<i64>,
|
|
pub name: String,
|
|
pub phone: Option<String>,
|
|
pub email: Option<String>,
|
|
pub address: Option<String>,
|
|
pub notes: Option<String>,
|
|
/// Unique token for the public media page (client views photos/videos here).
|
|
#[model(unique)]
|
|
pub media_token: String,
|
|
/// Hex color for calendar display, e.g. "#7c6ed4"
|
|
pub color: Option<String>,
|
|
/// active | archived
|
|
pub status: String,
|
|
pub created_at: chrono::NaiveDateTime,
|
|
pub updated_at: chrono::NaiveDateTime,
|
|
}
|
|
|
|
/// A scheduled pet-sitting visit.
|
|
#[derive(Debug, Clone)]
|
|
#[model]
|
|
pub struct Visit {
|
|
#[model(primary_key)]
|
|
pub id: Auto<i64>,
|
|
pub client_id: ForeignKey<Client>,
|
|
pub user_id: ForeignKey<User>,
|
|
pub visit_date: chrono::NaiveDate,
|
|
pub time_start: String,
|
|
pub time_end: String,
|
|
pub notes: Option<String>,
|
|
/// Public notes visible to client on their portal.
|
|
pub public_notes: Option<String>,
|
|
/// Feedback text from client via portal.
|
|
pub client_feedback: Option<String>,
|
|
/// scheduled | completed | cancelled | deleted
|
|
pub status: String,
|
|
pub created_at: chrono::NaiveDateTime,
|
|
pub updated_at: chrono::NaiveDateTime,
|
|
}
|
|
|
|
/// A photo or video uploaded for a client (optionally tied to a visit).
|
|
#[derive(Debug, Clone)]
|
|
#[model]
|
|
pub struct Media {
|
|
#[model(primary_key)]
|
|
pub id: Auto<i64>,
|
|
pub client_id: ForeignKey<Client>,
|
|
pub visit_id: Option<ForeignKey<Visit>>,
|
|
pub file_path: String,
|
|
/// photo | video
|
|
pub file_type: String,
|
|
pub caption: Option<String>,
|
|
/// active | archived
|
|
pub status: String,
|
|
pub created_at: chrono::NaiveDateTime,
|
|
}
|
|
|
|
/// An admin user who can log in to manage the system.
|
|
#[derive(Debug, Clone)]
|
|
#[model]
|
|
pub struct User {
|
|
#[model(primary_key)]
|
|
pub id: Auto<i64>,
|
|
#[model(unique)]
|
|
pub login: String,
|
|
pub password_hash: String,
|
|
pub display_name: Option<String>,
|
|
pub telegram_chat_id: Option<String>,
|
|
pub telegram_notifications: Option<bool>,
|
|
/// active | archived
|
|
pub status: String,
|
|
pub created_at: chrono::NaiveDateTime,
|
|
pub updated_at: chrono::NaiveDateTime,
|
|
}
|
|
|
|
/// A testimonial/review displayed on the landing page.
|
|
#[derive(Debug, Clone)]
|
|
#[model]
|
|
pub struct Testimonial {
|
|
#[model(primary_key)]
|
|
pub id: Auto<i64>,
|
|
pub text: String,
|
|
/// Optional short note (e.g. client name, pet type).
|
|
pub author_note: Option<String>,
|
|
/// Optional image path.
|
|
pub image_path: Option<String>,
|
|
/// active | hidden
|
|
pub status: String,
|
|
pub sort_order: i32,
|
|
pub created_at: chrono::NaiveDateTime,
|
|
}
|
|
|
|
/// Global key-value settings (telegram_bot_token, telegram_chat_id, etc.).
|
|
#[derive(Debug, Clone)]
|
|
#[model]
|
|
pub struct Setting {
|
|
#[model(primary_key)]
|
|
pub id: Auto<i64>,
|
|
#[model(unique)]
|
|
pub key: String,
|
|
pub value: String,
|
|
pub updated_at: chrono::NaiveDateTime,
|
|
}
|
|
|
|
/// A browser Web Push subscription belonging to a client device.
|
|
#[derive(Debug, Clone)]
|
|
#[model]
|
|
pub struct PushSubscription {
|
|
#[model(primary_key)]
|
|
pub id: Auto<i64>,
|
|
pub client_id: ForeignKey<Client>,
|
|
#[model(unique)]
|
|
pub endpoint: String,
|
|
pub p256dh: String,
|
|
pub auth: String,
|
|
pub language: String,
|
|
/// active | archived
|
|
pub status: String,
|
|
pub created_at: chrono::NaiveDateTime,
|
|
pub updated_at: chrono::NaiveDateTime,
|
|
}
|