Skip to content

Commit

Permalink
implement Contact & Lead Model, refs #8,#7,#6,#4
Browse files Browse the repository at this point in the history
  • Loading branch information
dmm1 committed Apr 18, 2024
1 parent e0a3f6f commit c92e579
Show file tree
Hide file tree
Showing 25 changed files with 742 additions and 137 deletions.
4 changes: 3 additions & 1 deletion crm/admin.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from django.contrib import admin
from django.contrib.auth.models import User
from .models import BusinessPartner, Opportunity
from .models import BusinessPartner, Opportunity, Lead, Contact

class OpportunityAdmin(admin.ModelAdmin):
pass

admin.site.register(BusinessPartner)
admin.site.register(Opportunity, OpportunityAdmin)
admin.site.register(Lead)
admin.site.register(Contact)
25 changes: 18 additions & 7 deletions crm/forms.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
from django import forms
from .models import Opportunity, BusinessPartner
from django.contrib.auth.models import User
from .models import Opportunity, BusinessPartner, Contact, Lead

class OpportunityForm(forms.ModelForm):
class Meta:
model = Opportunity
fields = ['name', 'customer', 'amount', 'probability', 'status']

class OpportunityForm(forms.ModelForm):
class Meta:
model = Opportunity
fields = ['name', 'customer', 'amount', 'probability', 'status']
class BusinessPartnerForm(forms.ModelForm):
user = forms.ModelChoiceField(queryset=User.objects.all(), required=False)
industry = forms.ChoiceField(choices=BusinessPartner.INDUSTRY_CHOICES)
primary_role = forms.ChoiceField(choices=BusinessPartner.PRIMARY_ROLE_CHOICES)
secondary_role = forms.ChoiceField(choices=BusinessPartner.SECONDARY_ROLE_CHOICES)

class BusinessParnterForm(forms.ModelForm):
class Meta:
model = BusinessPartner
fields = ['name', 'email', 'phone', 'industry', 'primary_role', 'secondary_role']
fields = ['name', 'name2', 'vat', 'email', 'phone', 'country', 'state', 'postcode', 'city', 'street_name', 'street_number', 'industry', 'primary_role', 'secondary_role', 'user']

class ContactForm(forms.ModelForm):
class Meta:
model = Contact
fields = ['first_name', 'last_name', 'academic_title', 'email', 'phone', 'title', 'job_function', 'business_partner', 'address', 'notes', 'last_contacted', 'preferred_communication']

class LeadForm(forms.ModelForm):
class Meta:
model = Lead
fields = ['name', 'email', 'phone', 'business_partner', 'contact', 'status', 'notes']
48 changes: 38 additions & 10 deletions crm/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Generated by Django 5.0.4 on 2024-04-17 20:57
# Generated by Django 5.0.4 on 2024-04-18 21:07

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
from crm.models import BusinessPartner


class Migration(migrations.Migration):

Expand All @@ -15,18 +15,46 @@ class Migration(migrations.Migration):

operations = [
migrations.CreateModel(
name='Customer',
name='BusinessPartner',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('name', models.CharField(default='', max_length=100)),
('name2', models.CharField(default='', max_length=100)),
('vat', models.CharField(default='', max_length=100)),
('email', models.EmailField(default='', max_length=100)),
('phone', models.CharField(default='', max_length=20)),
('country', models.CharField(default='', max_length=100)),
('state', models.CharField(default='', max_length=100)),
('postcode', models.CharField(default='', max_length=20)),
('city', models.CharField(default='', max_length=100)),
('street_name', models.CharField(default='', max_length=200)),
('street_number', models.CharField(default='', max_length=20)),
('industry', models.CharField(default='', max_length=200)),
('primary_role', models.CharField(default='', max_length=100)),
('secondary_role', models.CharField(default='', max_length=100)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='customers', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='Contact',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('first_name', models.CharField(default='', max_length=50)),
('last_name', models.CharField(default='', max_length=50)),
('academic_title', models.CharField(blank=True, max_length=50, null=True)),
('email', models.EmailField(max_length=100)),
('phone', models.CharField(max_length=20)),
('primary_role', models.CharField(blank=True, default='Customer', max_length=100, null=True, verbose_name='Primary Role')),
('secondary_role', models.CharField(blank=True, default='Merchant', max_length=100, null=True, verbose_name='Secondary Role')),
('industry', models.CharField(choices=[('Manufacturing', 'Manufacturing'), ('Retail', 'Retail'), ('Healthcare', 'Healthcare'), ('Technology', 'Technology'), ('Finance', 'Finance'), ('Education', 'Education'), ('Construction', 'Construction'), ('Transportation', 'Transportation'), ('Agriculture', 'Agriculture'), ('Energy', 'Energy')], max_length=50)),
('title', models.CharField(choices=[('Manager', 'Manager'), ('Director', 'Director'), ('Executive', 'Executive'), ('Other', 'Other')], max_length=50)),
('job_function', models.CharField(choices=[('Sales', 'Sales'), ('Marketing', 'Marketing'), ('IT', 'IT'), ('Finance', 'Finance'), ('HR', 'HR'), ('Other', 'Other')], max_length=50)),
('address', models.CharField(blank=True, max_length=200, null=True)),
('notes', models.TextField(blank=True, null=True)),
('last_contacted', models.DateTimeField(blank=True, null=True)),
('preferred_communication', models.CharField(blank=True, choices=[('Email', 'Email'), ('Phone', 'Phone'), ('Text', 'Text'), ('In-Person', 'In-Person')], max_length=50, null=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='customers', to=settings.AUTH_USER_MODEL)),
('business_partner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='contacts', to='crm.businesspartner')),
],
),
migrations.CreateModel(
Expand All @@ -36,11 +64,11 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=100)),
('amount', models.DecimalField(decimal_places=2, max_digits=10)),
('probability', models.IntegerField(default=50)),
('status', models.CharField(choices=[('open', 'Open'), ('won', 'Won'), ('lost', 'Lost')], max_length=50)),
('status', models.CharField(choices=[('open', 'Open'), ('won', 'Won'), ('lost', 'Lost'), ('finished', 'finished'), ('in progress', 'in progress')], max_length=50)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('assigned_to', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to=settings.AUTH_USER_MODEL)),
('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to='crm.customer')),
('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to='crm.businesspartner')),
],
),
]
23 changes: 0 additions & 23 deletions crm/migrations/0002_alter_customer_primary_role_and_more.py

This file was deleted.

18 changes: 0 additions & 18 deletions crm/migrations/0003_alter_customer_secondary_role.py

This file was deleted.

18 changes: 0 additions & 18 deletions crm/migrations/0004_alter_opportunity_status.py

This file was deleted.

19 changes: 0 additions & 19 deletions crm/migrations/0005_rename_customer_businesspartner.py

This file was deleted.

96 changes: 89 additions & 7 deletions crm/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,27 @@ class BusinessPartner(models.Model):
('-', '-'),
]

name = models.CharField(max_length=100)
email = models.EmailField(max_length=100)
phone = models.CharField(max_length=20)
primary_role = models.CharField(_("Primary Role"), max_length=100, choices=PRIMARY_ROLE_CHOICES, default='customer')
secondary_role = models.CharField(_("Secondary Role"), max_length=100, choices=SECONDARY_ROLE_CHOICES, default='merchant')
industry = models.CharField(max_length=50, choices=INDUSTRY_CHOICES)
name = models.CharField(max_length=100, default='')
name2 = models.CharField(max_length=100, default='')
vat = models.CharField(max_length=100, default='')
email = models.EmailField(max_length=100, default='')
phone = models.CharField(max_length=20, default='')
country = models.CharField(max_length=100, default='')
state = models.CharField(max_length=100, default='')
postcode = models.CharField(max_length=20, default='')
city = models.CharField(max_length=100, default='')
street_name = models.CharField(max_length=200, default='')
street_number = models.CharField(max_length=20, default='')
industry = models.CharField(max_length=200, default='')
primary_role = models.CharField(max_length=100, default='')
secondary_role = models.CharField(max_length=100, default='')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='customers')

def get_full_address(self):
return f"{self.street_number} {self.street_name}, {self.city}, {self.state} {self.postcode}, {self.country}"

def __str__(self):
return self.name

Expand All @@ -60,4 +71,75 @@ class Opportunity(models.Model):

def __str__(self):
return self.name
# Create your models here.
# Create your models here
class Contact(models.Model):
TITLE_CHOICES = [
('Manager', 'Manager'),
('Director', 'Director'),
('Executive', 'Executive'),
('Other', 'Other'),
]

JOB_FUNCTION_CHOICES = [
('Sales', 'Sales'),
('Marketing', 'Marketing'),
('IT', 'IT'),
('Finance', 'Finance'),
('HR', 'HR'),
('Other', 'Other'),
]

PREFERRED_COMMUNICATION_CHOICES = [
('Email', 'Email'),
('Phone', 'Phone'),
('Text', 'Text'),
('In-Person', 'In-Person'),
]

first_name = models.CharField(max_length=50, default='')
last_name = models.CharField(max_length=50, default='')
academic_title = models.CharField(max_length=50, null=True, blank=True)
email = models.EmailField(max_length=100)
phone = models.CharField(max_length=20)
title = models.CharField(max_length=50, choices=TITLE_CHOICES)
job_function = models.CharField(max_length=50, choices=JOB_FUNCTION_CHOICES)
business_partner = models.ForeignKey(BusinessPartner, on_delete=models.CASCADE, related_name='contacts', null=True, blank=True)
address = models.CharField(max_length=200, null=True, blank=True)
notes = models.TextField(null=True, blank=True)
last_contacted = models.DateTimeField(null=True, blank=True)
preferred_communication = models.CharField(max_length=50, choices=PREFERRED_COMMUNICATION_CHOICES, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

def __str__(self):
if self.academic_title:
return f"{self.academic_title} {self.first_name} {self.last_name}"
else:
return f"{self.first_name} {self.last_name}"

def get_address(self):
if self.business_partner:
return self.business_partner.address
else:
return self.address

LEAD_STATUS_CHOICES = [
('New', 'New'),
('Open', 'Open'),
('Contacted', 'Contacted'),
('Qualified', 'Qualified'),
('Won', 'Won'),
('Lost', 'Lost'),
]

class Lead(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
phone = models.CharField(max_length=20, blank=True, null=True)
business_partner = models.ForeignKey(BusinessPartner, on_delete=models.CASCADE, related_name='leads', blank=True, null=True)
contact = models.ForeignKey(Contact, on_delete=models.CASCADE, related_name='leads', blank=True, null=True)
status = models.CharField(max_length=50, choices=LEAD_STATUS_CHOICES, default='New')
notes = models.TextField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='leads')
10 changes: 10 additions & 0 deletions crm/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,14 @@
path('opportunities/<int:pk>/', views.opportunity_detail, name='opportunity_detail'),
path('opportunities/<int:pk>/update/', views.opportunity_update, name='opportunity_update'),
path('opportunities/<int:pk>/delete/', views.opportunity_delete, name='opportunity_delete'),
path('contacts/', views.contact_list, name='contact_list'),
path('contacts/create/', views.contact_create, name='contact_create'),
path('contacts/<int:pk>/', views.contact_detail, name='contact_detail'),
path('contacts/<int:pk>/update/', views.contact_update, name='contact_update'),
path('contacts/<int:pk>/delete/', views.contact_delete, name='contact_delete'),
path('leads/', views.lead_list, name='lead_list'),
path('leads/create/', views.lead_create, name='lead_create'),
path('leads/<int:pk>/', views.lead_detail, name='lead_detail'),
path('leads/<int:pk>/update/', views.lead_update, name='lead_update'),
path('leads/<int:pk>/delete/', views.lead_delete, name='lead_delete'),
]
Loading

0 comments on commit c92e579

Please sign in to comment.