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.
221 lines
8.3 KiB
221 lines
8.3 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
|
|
|
|
import uuid
|
|
|
|
from sync.models import BaseModel
|
|
|
|
User = get_user_model()
|
|
|
|
class Status(models.TextChoices):
|
|
NONE = 'NONE', 'None'
|
|
INBOUND = 'INBOUND', 'Inbound'
|
|
CONTACTED = 'CONTACTED', 'Contacted'
|
|
RESPONDED = 'RESPONDED', 'Responded'
|
|
SHOULD_TEST = 'SHOULD_TEST', 'Should test'
|
|
TESTING = 'TESTING', 'Testing'
|
|
CUSTOMER = 'CUSTOMER', 'Customer'
|
|
LOST = 'LOST', 'Lost customer'
|
|
DECLINED = 'DECLINED', 'Declined'
|
|
# DECLINED_UNRELATED = 'DECLINED_UNRELATED', 'Declined without significance'
|
|
NOT_CONCERNED = 'NOT_CONCERNED', 'Not concerned'
|
|
SHOULD_BUY = 'SHOULD_BUY', 'Should buy'
|
|
HAVE_CREATED_ACCOUNT = 'HAVE_CREATED_ACCOUNT', 'Have created account'
|
|
|
|
class DeclinationReason(models.TextChoices):
|
|
TOO_EXPENSIVE = 'TOO_EXPENSIVE', 'Too expensive'
|
|
USE_OTHER_PRODUCT = 'USE_OTHER_PRODUCT', 'Use other product'
|
|
USE_ANDROID = 'USE_ANDROID', 'Use Android'
|
|
TOO_FEW_TOURNAMENTS = 'TOO_FEW_TOURNAMENTS', 'Too few tournaments'
|
|
NOT_INTERESTED = 'NOT_INTERESTED', 'Not interested'
|
|
UNKNOWN = 'UNKNOWN', 'Unknown'
|
|
|
|
class ActivityType(models.TextChoices):
|
|
MAIL = 'MAIL', 'Mail'
|
|
SMS = 'SMS', 'SMS'
|
|
CALL = 'CALL', 'Call'
|
|
PRESS = 'PRESS', 'Press Release'
|
|
WORD_OF_MOUTH = 'WORD_OF_MOUTH', 'Word of mouth'
|
|
WHATS_APP = 'WHATS_APP', 'WhatsApp'
|
|
|
|
class Entity(BaseModel):
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
|
|
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):
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
|
|
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, null=True, blank=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)
|
|
contact_again = models.DateTimeField(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 Status.NONE
|
|
|
|
def current_activity_type(self):
|
|
last_activity = self.activities.exclude(type=None).order_by('-creation_date').first()
|
|
if last_activity:
|
|
return last_activity.type
|
|
return None
|
|
|
|
def current_text(self):
|
|
last_activity = self.activities.exclude(status=None).order_by('-creation_date').first()
|
|
if last_activity:
|
|
return last_activity.attachment_text
|
|
return ''
|
|
|
|
def current_declination_reason(self):
|
|
last_activity = self.activities.exclude(status=None).order_by('-creation_date').first()
|
|
if last_activity:
|
|
return last_activity.declination_reason
|
|
return None
|
|
|
|
def entity_names(self):
|
|
entity_names = [entity.name for entity in self.entities.all()]
|
|
return " - ".join(entity_names)
|
|
|
|
def full_name(self):
|
|
if self.first_name and self.last_name:
|
|
return f'{self.first_name} {self.last_name}'
|
|
elif self.first_name:
|
|
return self.first_name
|
|
elif self.last_name:
|
|
return self.last_name
|
|
else:
|
|
return 'no name'
|
|
|
|
def __str__(self):
|
|
return self.full_name()
|
|
|
|
class Activity(BaseModel):
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
|
|
status = models.CharField(max_length=50, choices=Status.choices, null=True, blank=True)
|
|
declination_reason = models.CharField(max_length=50, choices=DeclinationReason.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
|
|
|
|
def save(self, *args, **kwargs):
|
|
super().save(*args, **kwargs)
|
|
# Update last_update for all related prospects when activity is saved
|
|
self.prospects.update(last_update=timezone.now())
|
|
|
|
class Meta:
|
|
verbose_name_plural = "Activities"
|
|
ordering = ['-creation_date']
|
|
|
|
# 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.status, self.declination_reason, self.attachment_text, self.description, self.type] 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
|
|
|
|
def prospect_names(self):
|
|
prospect_names = [prospect.full_name() for prospect in self.prospects.all()]
|
|
return ", ".join(prospect_names)
|
|
|
|
@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(),contact_again=None)
|
|
|
|
class EmailTemplate(BaseModel):
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
|
|
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
|
|
|
|
def delete_dependencies(self):
|
|
pass
|
|
|
|
class ProspectGroup(BaseModel):
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
|
|
name = models.CharField(max_length=200, null=True, blank=True)
|
|
prospects = models.ManyToManyField(Prospect, blank=True, related_name='prospect_groups')
|
|
|
|
def user_count(self):
|
|
return self.prospects.count()
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
def delete_dependencies(self):
|
|
pass
|
|
|
|
# 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']
|
|
|