backbone-mailing 0.4.0

Email marketing — mass-mail engine: audiences, subscriptions, hand-set mailing lifecycle, seeded A/B testing, per-recipient traces, cycle-44 bridge targets (Odoo mass_mailing port)
//! Domain Entities
//!
//! Generated by metaphor-schema. Do not edit manually.

pub mod mailing_ab_test;
pub mod mailing_audience;
pub mod mailing_contact;
pub mod mailing_subscription;
pub mod opt_out_reason;
pub mod mailing;
pub mod mailing_trace;
pub mod mailing_filter;
pub mod ab_winner_selection;
pub mod mailing_state;
pub mod mailing_schedule_type;
pub mod mailing_type;
pub mod mailing_target_model;
pub mod trace_type;
pub mod trace_status;
pub mod trace_failure_type;

// Re-exports
pub use mailing_ab_test::MailingAbTest;
pub use mailing_ab_test::MailingAbTestBuilder;
pub use mailing_ab_test::MailingAbTestId;
pub use mailing_audience::MailingAudience;
pub use mailing_audience::MailingAudienceBuilder;
pub use mailing_audience::MailingAudienceId;
pub use mailing_contact::MailingContact;
pub use mailing_contact::MailingContactBuilder;
pub use mailing_contact::MailingContactId;
pub use mailing_subscription::MailingSubscription;
pub use mailing_subscription::MailingSubscriptionBuilder;
pub use mailing_subscription::MailingSubscriptionId;
pub use opt_out_reason::OptOutReason;
pub use opt_out_reason::OptOutReasonBuilder;
pub use opt_out_reason::OptOutReasonId;
pub use mailing::Mailing;
pub use mailing::MailingBuilder;
pub use mailing::MailingId;
pub use mailing_trace::MailingTrace;
pub use mailing_trace::MailingTraceBuilder;
pub use mailing_trace::MailingTraceId;
pub use mailing_filter::MailingFilter;
pub use mailing_filter::MailingFilterBuilder;
pub use mailing_filter::MailingFilterId;
pub use ab_winner_selection::AbWinnerSelection;
pub use mailing_state::MailingState;
pub use mailing_schedule_type::MailingScheduleType;
pub use mailing_type::MailingType;
pub use mailing_target_model::MailingTargetModel;
pub use trace_type::TraceType;
pub use trace_status::TraceStatus;
pub use trace_failure_type::TraceFailureType;

// ==========================================================================
// Entity Trait
// ==========================================================================

use std::fmt::Debug;

/// Trait for domain entities
///
/// All generated entities implement this trait, providing
/// a common interface for working with domain objects.
pub trait Entity: Debug + Clone {
    /// The type of the entity's unique identifier
    type Id: Debug + Clone + PartialEq;

    /// Get the entity's unique identifier
    fn entity_id(&self) -> &Self::Id;

    /// Get the entity type name
    fn entity_type() -> &'static str;
}

// ==========================================================================
// Audit Metadata
// ==========================================================================

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[cfg(feature = "openapi")]
use utoipa::ToSchema;

/// Audit metadata stored as JSONB in the database
///
/// This struct consolidates audit fields (timestamps and actors) into a single
/// JSONB column for efficient storage and flexible querying.
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct AuditMetadata {
    /// Timestamp when the record was created
    #[serde(skip_serializing_if = "Option::is_none")]
    pub created_at: Option<DateTime<Utc>>,

    /// Timestamp when the record was last updated
    #[serde(skip_serializing_if = "Option::is_none")]
    pub updated_at: Option<DateTime<Utc>>,

    /// Timestamp when the record was soft-deleted
    #[serde(skip_serializing_if = "Option::is_none")]
    pub deleted_at: Option<DateTime<Utc>>,

    /// User ID who created the record
    #[serde(skip_serializing_if = "Option::is_none")]
    pub created_by: Option<Uuid>,

    /// User ID who last updated the record
    #[serde(skip_serializing_if = "Option::is_none")]
    pub updated_by: Option<Uuid>,

    /// User ID who deleted the record
    #[serde(skip_serializing_if = "Option::is_none")]
    pub deleted_by: Option<Uuid>,
}

impl AuditMetadata {
    /// Create new audit metadata with created_at set to now
    pub fn new() -> Self {
        Self {
            created_at: Some(Utc::now()),
            ..Default::default()
        }
    }

    /// Create with creator ID
    pub fn with_creator(creator_id: Uuid) -> Self {
        Self {
            created_at: Some(Utc::now()),
            created_by: Some(creator_id),
            ..Default::default()
        }
    }

    /// Touch the record (update updated_at)
    pub fn touch(&mut self) {
        self.updated_at = Some(Utc::now());
    }

    /// Touch with updater ID
    pub fn touch_by(&mut self, updater_id: Uuid) {
        self.updated_at = Some(Utc::now());
        self.updated_by = Some(updater_id);
    }

    /// Soft delete the record
    pub fn soft_delete(&mut self) {
        self.deleted_at = Some(Utc::now());
    }

    /// Soft delete with deleter ID
    pub fn soft_delete_by(&mut self, deleter_id: Uuid) {
        self.deleted_at = Some(Utc::now());
        self.deleted_by = Some(deleter_id);
    }

    /// Restore a soft-deleted record
    pub fn restore(&mut self) {
        self.deleted_at = None;
        self.deleted_by = None;
    }

    /// Check if record is deleted
    pub fn is_deleted(&self) -> bool {
        self.deleted_at.is_some()
    }

    /// Check if record is active (not deleted)
    pub fn is_active(&self) -> bool {
        self.deleted_at.is_none()
    }
}