Some checks failed
Migrates scanning pipeline from marketing-.lu-domains app into Orion module. Supports digital (domain scan) and offline (manual capture) lead channels with enrichment, scoring, campaign management, and interaction tracking. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
84 lines
2.4 KiB
Python
84 lines
2.4 KiB
Python
# app/modules/prospecting/models/campaign.py
|
|
"""
|
|
Campaign templates and send tracking.
|
|
|
|
Templates are tailored by lead type (no_website, bad_website, etc.)
|
|
with support for multiple languages and delivery channels.
|
|
"""
|
|
|
|
import enum
|
|
|
|
from sqlalchemy import (
|
|
Boolean,
|
|
Column,
|
|
DateTime,
|
|
Enum,
|
|
ForeignKey,
|
|
Integer,
|
|
String,
|
|
Text,
|
|
)
|
|
|
|
from app.core.database import Base
|
|
from models.database.base import TimestampMixin
|
|
|
|
|
|
class LeadType(str, enum.Enum):
|
|
NO_WEBSITE = "no_website"
|
|
BAD_WEBSITE = "bad_website"
|
|
GMAIL_ONLY = "gmail_only"
|
|
SECURITY_ISSUES = "security_issues"
|
|
PERFORMANCE_ISSUES = "performance_issues"
|
|
OUTDATED_CMS = "outdated_cms"
|
|
GENERAL = "general"
|
|
|
|
|
|
class CampaignChannel(str, enum.Enum):
|
|
EMAIL = "email"
|
|
LETTER = "letter"
|
|
PHONE_SCRIPT = "phone_script"
|
|
|
|
|
|
class CampaignSendStatus(str, enum.Enum):
|
|
DRAFT = "draft"
|
|
SENT = "sent"
|
|
DELIVERED = "delivered"
|
|
OPENED = "opened"
|
|
BOUNCED = "bounced"
|
|
REPLIED = "replied"
|
|
|
|
|
|
class CampaignTemplate(Base, TimestampMixin):
|
|
"""A reusable marketing campaign template."""
|
|
|
|
__tablename__ = "campaign_templates"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
name = Column(String(255), nullable=False)
|
|
lead_type = Column(Enum(LeadType), nullable=False)
|
|
channel = Column(Enum(CampaignChannel), nullable=False, default=CampaignChannel.EMAIL)
|
|
language = Column(String(5), nullable=False, default="fr")
|
|
|
|
subject_template = Column(String(500), nullable=True)
|
|
body_template = Column(Text, nullable=False)
|
|
|
|
is_active = Column(Boolean, nullable=False, default=True)
|
|
|
|
|
|
class CampaignSend(Base, TimestampMixin):
|
|
"""A record of a campaign sent to a specific prospect."""
|
|
|
|
__tablename__ = "campaign_sends"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
template_id = Column(Integer, ForeignKey("campaign_templates.id", ondelete="SET NULL"), nullable=True)
|
|
prospect_id = Column(Integer, ForeignKey("prospects.id", ondelete="CASCADE"), nullable=False, index=True)
|
|
|
|
channel = Column(Enum(CampaignChannel), nullable=False)
|
|
rendered_subject = Column(String(500), nullable=True)
|
|
rendered_body = Column(Text, nullable=True)
|
|
|
|
status = Column(Enum(CampaignSendStatus), nullable=False, default=CampaignSendStatus.DRAFT)
|
|
sent_at = Column(DateTime, nullable=True)
|
|
sent_by_user_id = Column(Integer, nullable=True)
|