You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
5.7 KiB
154 lines
5.7 KiB
from typing import Self
|
|
from django.db import models
|
|
from django.contrib.auth import get_user_model
|
|
|
|
from django.db.models.signals import m2m_changed
|
|
from django.dispatch import receiver
|
|
from django.utils import timezone
|
|
|
|
from sync.models import BaseModel
|
|
|
|
User = get_user_model()
|
|
|
|
class Status(models.TextChoices):
|
|
NONE = 'NONE', 'None'
|
|
CONTACTED = 'CONTACTED', 'Contacted'
|
|
RESPONDED = 'RESPONDED', 'Responded'
|
|
SHOULD_TEST = 'SHOULD_TEST', 'Should test'
|
|
TESTING = 'TESTING', 'Testing'
|
|
CUSTOMER = 'CUSTOMER', 'Customer'
|
|
LOST = 'LOST', 'Lost customer'
|
|
DECLINED_TOO_EXPENSIVE = 'DECLINED_TOO_EXPENSIVE', 'Too expensive'
|
|
DECLINED_USE_SOMETHING_ELSE = 'DECLINED_USE_SOMETHING_ELSE', 'Use something else'
|
|
DECLINED_OTHER = 'DECLINED_OTHER', 'Declined other reason'
|
|
DECLINED_UNRELATED = 'DECLINED_UNRELATED', 'Declined without significance'
|
|
|
|
class ActivityType(models.TextChoices):
|
|
MAIL = 'MAIL', 'Mailing List'
|
|
SMS = 'SMS', 'SMS Campaign'
|
|
CALL = 'CALL', 'Call'
|
|
PRESS = 'PRESS', 'Press Release'
|
|
|
|
class Entity(BaseModel):
|
|
name = models.CharField(max_length=200, null=True, blank=True)
|
|
address = models.CharField(max_length=200, null=True, blank=True)
|
|
zip_code = models.CharField(max_length=20, null=True, blank=True)
|
|
city = models.CharField(max_length=500, null=True, blank=True)
|
|
official_user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
|
|
# status = models.IntegerField(default=Status.NONE, choices=Status.choices)
|
|
|
|
def delete_dependencies(self):
|
|
pass
|
|
|
|
class Meta:
|
|
verbose_name_plural = "Entities"
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
class Prospect(BaseModel):
|
|
first_name = models.CharField(max_length=200, null=True, blank=True)
|
|
last_name = models.CharField(max_length=200, null=True, blank=True)
|
|
email = models.EmailField(unique=True)
|
|
phone = models.CharField(max_length=25, null=True, blank=True)
|
|
name_unsure = models.BooleanField(default=False)
|
|
official_user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
|
|
|
|
entities = models.ManyToManyField(Entity, blank=True, related_name='prospects')
|
|
source = models.CharField(max_length=100, null=True, blank=True)
|
|
|
|
def delete_dependencies(self):
|
|
pass
|
|
|
|
class Meta:
|
|
permissions = [
|
|
("manage_prospects", "Can manage prospects"),
|
|
("view_prospects", "Can view prospects"),
|
|
]
|
|
|
|
def current_status(self):
|
|
last_activity = self.activities.exclude(status=None).order_by('-creation_date').first()
|
|
if last_activity:
|
|
return last_activity.status
|
|
return None
|
|
|
|
def entity_names(self):
|
|
entity_names = [entity.name for entity in self.entities.all()]
|
|
return " - ".join(entity_names)
|
|
|
|
def full_name(self):
|
|
return f'{self.first_name} {self.last_name}'
|
|
|
|
def __str__(self):
|
|
return self.full_name()
|
|
|
|
class Activity(BaseModel):
|
|
status = models.CharField(max_length=50, default=Status.NONE, choices=Status.choices, null=True, blank=True)
|
|
type = models.CharField(max_length=20, choices=ActivityType.choices, null=True, blank=True)
|
|
description = models.TextField(null=True, blank=True)
|
|
attachment_text = models.TextField(null=True, blank=True)
|
|
prospects = models.ManyToManyField(Prospect, related_name='activities')
|
|
|
|
def __str__(self):
|
|
if self.status:
|
|
return self.status
|
|
elif self.type:
|
|
return self.type
|
|
else:
|
|
return f'desc = {self.description}, attachment_text = {self.attachment_text}'
|
|
|
|
def delete_dependencies(self):
|
|
pass
|
|
|
|
class Meta:
|
|
verbose_name_plural = "Activities"
|
|
ordering = ['-creation_date']
|
|
permissions = [
|
|
("manage_events", "Can manage events"),
|
|
("view_events", "Can view events"),
|
|
]
|
|
|
|
def __str__(self):
|
|
return f"{self.get_type_display()} - {self.creation_date.date()}"
|
|
|
|
def html_desc(self):
|
|
fields = [field for field in [self.creation_date.strftime("%d/%m/%Y %H:%M"), self.type, self.status, self.attachment_text, self.description] if field is not None]
|
|
html = '<table><tr>'
|
|
for field in fields:
|
|
html += f'<td style="padding:0px 5px;">{field}</td>'
|
|
html += '</tr></table>'
|
|
return html
|
|
|
|
@receiver(m2m_changed, sender=Activity.prospects.through)
|
|
def update_prospect_last_update(sender, instance, action, pk_set, **kwargs):
|
|
instance.prospects.update(last_update=timezone.now())
|
|
|
|
class EmailTemplate(BaseModel):
|
|
name = models.CharField(max_length=100)
|
|
subject = models.CharField(max_length=200)
|
|
body = models.TextField(null=True, blank=True)
|
|
activities = models.ManyToManyField(Activity, blank=True, related_name='email_templates')
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
# class EmailCampaign(models.Model):
|
|
# event = models.OneToOneField(Event, on_delete=models.CASCADE)
|
|
# subject = models.CharField(max_length=200)
|
|
# content = models.TextField()
|
|
# sent_at = models.DateTimeField(null=True, blank=True)
|
|
|
|
# class EmailTracker(models.Model):
|
|
# campaign = models.ForeignKey(EmailCampaign, on_delete=models.CASCADE)
|
|
# prospect = models.ForeignKey(Prospect, on_delete=models.CASCADE)
|
|
# tracking_id = models.UUIDField(default=uuid.uuid4, editable=False)
|
|
# sent = models.BooleanField(default=False)
|
|
# sent_at = models.DateTimeField(null=True, blank=True)
|
|
# opened = models.BooleanField(default=False)
|
|
# opened_at = models.DateTimeField(null=True, blank=True)
|
|
# clicked = models.BooleanField(default=False)
|
|
# clicked_at = models.DateTimeField(null=True, blank=True)
|
|
# error_message = models.TextField(blank=True)
|
|
|
|
# class Meta:
|
|
# unique_together = ['campaign', 'prospect']
|
|
|