├── .gitignore ├── Pipfile ├── Pipfile.lock ├── README.md ├── accounts ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── serializers.py ├── tests.py └── views.py ├── contacts ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── serializers.py ├── tests.py └── views.py ├── db.sqlite3 ├── leads ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── serializers.py ├── tests.py └── views.py ├── manage.py ├── opportunities ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── serializers.py ├── tests.py └── views.py └── simplecrm ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.python.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [dev-packages] 7 | 8 | [packages] 9 | django = "*" 10 | djangorestframework = "*" 11 | django-cors-headers = "*" 12 | 13 | [requires] 14 | python_version = "3.5" 15 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "098f8d4da61ccc86efa70ddbd8d3a23a0b71b1f1dd7831a8fd8dc272fbdcad7e" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.5" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.python.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "django": { 20 | "hashes": [ 21 | "sha256:26b34f4417aa38d895b6b5307177b51bc3f4d53179d8696a5c19dcb50582523c", 22 | "sha256:71d1a584bb4ad2b4f933d07d02c716755c1394feaac1ce61ce37843ac5401092" 23 | ], 24 | "index": "pypi", 25 | "version": "==2.0.5" 26 | }, 27 | "django-cors-headers": { 28 | "hashes": [ 29 | "sha256:0e9532628b3aa8806442d4d0b15e56112e6cfbef3735e13401935c98b842a2b4", 30 | "sha256:c7ec4816ec49416517b84f317499d1519db62125471922ab78d670474ed9b987" 31 | ], 32 | "index": "pypi", 33 | "version": "==2.2.0" 34 | }, 35 | "djangorestframework": { 36 | "hashes": [ 37 | "sha256:b6714c3e4b0f8d524f193c91ecf5f5450092c2145439ac2769711f7eba89a9d9", 38 | "sha256:c375e4f95a3a64fccac412e36fb42ba36881e52313ec021ef410b40f67cddca4" 39 | ], 40 | "index": "pypi", 41 | "version": "==3.8.2" 42 | }, 43 | "pytz": { 44 | "hashes": [ 45 | "sha256:65ae0c8101309c45772196b21b74c46b2e5d11b6275c45d251b150d5da334555", 46 | "sha256:c06425302f2cf668f1bba7a0a03f3c1d34d4ebeef2c72003da308b3947c7f749" 47 | ], 48 | "version": "==2018.4" 49 | } 50 | }, 51 | "develop": {} 52 | } 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Simple Django CRM (Customer Relationship Management) Project 2 | 3 | This project contains Models and Django REST framework API for a simple CRM web application. 4 | 5 | 6 | You can read this [tutorial](https://www.techiediaries.com/angular-tutorial) accompanying this repository for more information. 7 | 8 | You can also check the [Angular 6 front-end](https://github.com/techiediaries/ng-crm). 9 | 10 | -------------------------------------------------------------------------------- /accounts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiediaries/django-crm/41b8f84a508f48b9d93e6cd33cbc2fe2707455cc/accounts/__init__.py -------------------------------------------------------------------------------- /accounts/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /accounts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountsConfig(AppConfig): 5 | name = 'accounts' 6 | -------------------------------------------------------------------------------- /accounts/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0.5 on 2018-05-04 21:37 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='Account', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('Name', models.CharField(max_length=64, verbose_name='Name of Account')), 22 | ('email', models.EmailField(max_length=254)), 23 | ('phone', models.CharField(max_length=20)), 24 | ('industry', models.CharField(blank=True, choices=[('FINANCE', 'FINANCE'), ('HEALTHCARE', 'HEALTHCARE'), ('INSURANCE', 'INSURANCE'), ('LEGAL', 'LEGAL'), ('MANUFACTURING', 'MANUFACTURING'), ('PUBLISHING', 'PUBLISHING'), ('REAL ESTATE', 'REAL ESTATE'), ('SOFTWARE', 'SOFTWARE')], max_length=255, null=True, verbose_name='Industry Type')), 25 | ('website', models.URLField(blank=True, null=True, verbose_name='Website')), 26 | ('description', models.TextField(blank=True, null=True)), 27 | ('createdOn', models.DateTimeField(auto_now_add=True, verbose_name='Created on')), 28 | ('isActive', models.BooleanField(default=False)), 29 | ('assigned_to', models.ManyToManyField(related_name='account_assigned_to', to=settings.AUTH_USER_MODEL)), 30 | ('createdBy', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='account_created_by', to=settings.AUTH_USER_MODEL)), 31 | ], 32 | ), 33 | ] 34 | -------------------------------------------------------------------------------- /accounts/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiediaries/django-crm/41b8f84a508f48b9d93e6cd33cbc2fe2707455cc/accounts/migrations/__init__.py -------------------------------------------------------------------------------- /accounts/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import User 3 | 4 | INDCHOICES = ( 5 | ('FINANCE', 'FINANCE'), 6 | ('HEALTHCARE', 'HEALTHCARE'), 7 | ('INSURANCE', 'INSURANCE'), 8 | ('LEGAL', 'LEGAL'), 9 | ('MANUFACTURING', 'MANUFACTURING'), 10 | ('PUBLISHING', 'PUBLISHING'), 11 | ('REAL ESTATE', 'REAL ESTATE'), 12 | ('SOFTWARE', 'SOFTWARE'), 13 | ) 14 | 15 | class Account(models.Model): 16 | name = models.CharField("Name of Account", "Name", max_length=64) 17 | email = models.EmailField() 18 | phone = models.CharField(max_length=20) 19 | industry = models.CharField("Industry Type", max_length=255, choices=INDCHOICES, blank=True, null=True) 20 | website = models.URLField("Website", blank=True, null=True) 21 | description = models.TextField(blank=True, null=True) 22 | assigned_to = models.ManyToManyField(User, related_name='account_assigned_to') 23 | createdBy = models.ForeignKey(User, related_name='account_created_by', on_delete=models.CASCADE) 24 | createdOn = models.DateTimeField("Created on", auto_now_add=True) 25 | isActive = models.BooleanField(default=False) 26 | 27 | def __str__(self): 28 | return self.name 29 | 30 | -------------------------------------------------------------------------------- /accounts/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from .models import Account 3 | 4 | class AccountSerializer(serializers.ModelSerializer): 5 | class Meta: 6 | model = Account 7 | fields = "__all__" -------------------------------------------------------------------------------- /accounts/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /accounts/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from rest_framework import generics 3 | from .models import Account 4 | from .serializers import AccountSerializer 5 | from rest_framework.permissions import IsAdminUser 6 | # Create your views here. 7 | 8 | class AccountListAPIView(generics.ListCreateAPIView): 9 | queryset = Account.objects.all() 10 | serializer_class = AccountSerializer 11 | #permission_classes = (IsAdminUser,) -------------------------------------------------------------------------------- /contacts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiediaries/django-crm/41b8f84a508f48b9d93e6cd33cbc2fe2707455cc/contacts/__init__.py -------------------------------------------------------------------------------- /contacts/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /contacts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ContactsConfig(AppConfig): 5 | name = 'contacts' 6 | -------------------------------------------------------------------------------- /contacts/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0.5 on 2018-05-04 22:27 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | ('accounts', '0001_initial'), 14 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='Contact', 20 | fields=[ 21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ('first_name', models.CharField(max_length=255, verbose_name='First name')), 23 | ('last_name', models.CharField(max_length=255, verbose_name='Last name')), 24 | ('email', models.EmailField(max_length=254)), 25 | ('phone', models.CharField(max_length=20)), 26 | ('address', models.TextField(blank=True, null=True)), 27 | ('description', models.TextField(blank=True, null=True)), 28 | ('createdOn', models.DateTimeField(auto_now_add=True, verbose_name='Created on')), 29 | ('isActive', models.BooleanField(default=False)), 30 | ('account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='lead_account_contacts', to='accounts.Account')), 31 | ('createdBy', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='contact_created_by', to=settings.AUTH_USER_MODEL)), 32 | ], 33 | ), 34 | ] 35 | -------------------------------------------------------------------------------- /contacts/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiediaries/django-crm/41b8f84a508f48b9d93e6cd33cbc2fe2707455cc/contacts/migrations/__init__.py -------------------------------------------------------------------------------- /contacts/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import User 3 | from accounts.models import Account 4 | 5 | class Contact(models.Model): 6 | first_name = models.CharField("First name", max_length=255) 7 | last_name = models.CharField("Last name", max_length=255) 8 | account = models.ForeignKey(Account, related_name='lead_account_contacts', on_delete=models.CASCADE, blank=True, null=True) 9 | email = models.EmailField() 10 | phone = models.CharField(max_length=20) 11 | address = models.TextField(blank=True, null=True) 12 | description = models.TextField(blank=True, null=True) 13 | createdBy = models.ForeignKey(User, related_name='contact_created_by', on_delete=models.CASCADE) 14 | createdOn = models.DateTimeField("Created on", auto_now_add=True) 15 | isActive = models.BooleanField(default=False) 16 | 17 | def __str__(self): 18 | return self.first_name 19 | -------------------------------------------------------------------------------- /contacts/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from .models import Contact 3 | 4 | class ContactSerializer(serializers.ModelSerializer): 5 | class Meta: 6 | model = Contact 7 | fields = "__all__" -------------------------------------------------------------------------------- /contacts/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /contacts/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from rest_framework import generics 3 | from .models import Contact 4 | from .serializers import ContactSerializer 5 | from rest_framework.permissions import IsAdminUser 6 | # Create your views here. 7 | 8 | class ContactListAPIView(generics.ListCreateAPIView): 9 | queryset = Contact.objects.all() 10 | serializer_class = ContactSerializer 11 | #permission_classes = (IsAdminUser,) -------------------------------------------------------------------------------- /db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiediaries/django-crm/41b8f84a508f48b9d93e6cd33cbc2fe2707455cc/db.sqlite3 -------------------------------------------------------------------------------- /leads/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiediaries/django-crm/41b8f84a508f48b9d93e6cd33cbc2fe2707455cc/leads/__init__.py -------------------------------------------------------------------------------- /leads/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /leads/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class LeadsConfig(AppConfig): 5 | name = 'leads' 6 | -------------------------------------------------------------------------------- /leads/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0.5 on 2018-05-04 22:27 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | ('accounts', '0001_initial'), 14 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='Lead', 20 | fields=[ 21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ('title', models.CharField(blank=True, max_length=64, null=True, verbose_name='Treatment Pronouns for the customer')), 23 | ('first_name', models.CharField(max_length=255, verbose_name='First name')), 24 | ('last_name', models.CharField(max_length=255, verbose_name='Last name')), 25 | ('email', models.EmailField(max_length=254)), 26 | ('phone', models.CharField(blank=True, max_length=20, null=True)), 27 | ('status', models.CharField(blank=True, choices=[('assigned', 'Assigned'), ('in process', 'In Process'), ('converted', 'Converted'), ('recycled', 'Recycled'), ('dead', 'Dead')], max_length=255, null=True, verbose_name='Status of Lead')), 28 | ('source', models.CharField(blank=True, choices=[('call', 'Call'), ('email', 'Email'), ('existing customer', 'Existing Customer'), ('partner', 'Partner'), ('public relations', 'Public Relations'), ('compaign', 'Campaign'), ('other', 'Other')], max_length=255, null=True, verbose_name='Source of Lead')), 29 | ('address', models.CharField(blank=True, max_length=255, null=True, verbose_name='Address')), 30 | ('website', models.CharField(blank=True, max_length=255, null=True, verbose_name='Website')), 31 | ('description', models.TextField(blank=True, null=True)), 32 | ('account_name', models.CharField(blank=True, max_length=255, null=True)), 33 | ('opportunity_amount', models.DecimalField(blank=True, decimal_places=2, max_digits=12, null=True, verbose_name='Opportunity Amount')), 34 | ('createdOn', models.DateTimeField(auto_now_add=True, verbose_name='Created on')), 35 | ('isActive', models.BooleanField(default=False)), 36 | ('enquery_type', models.CharField(blank=True, max_length=255, null=True)), 37 | ('account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='Leads', to='accounts.Account')), 38 | ('assigned_to', models.ManyToManyField(related_name='lead_assigned_users', to=settings.AUTH_USER_MODEL)), 39 | ('createdBy', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='lead_created_by', to=settings.AUTH_USER_MODEL)), 40 | ], 41 | ), 42 | ] 43 | -------------------------------------------------------------------------------- /leads/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiediaries/django-crm/41b8f84a508f48b9d93e6cd33cbc2fe2707455cc/leads/migrations/__init__.py -------------------------------------------------------------------------------- /leads/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import User 3 | from accounts.models import Account 4 | 5 | LEAD_SOURCE = ( 6 | ('call', 'Call'), 7 | ('email', 'Email'), 8 | ('existing customer', 'Existing Customer'), 9 | ('partner', 'Partner'), 10 | ('public relations', 'Public Relations'), 11 | ('compaign', 'Campaign'), 12 | ('other', 'Other'), 13 | ) 14 | 15 | LEAD_STATUS = ( 16 | ('assigned', 'Assigned'), 17 | ('in process', 'In Process'), 18 | ('converted', 'Converted'), 19 | ('recycled', 'Recycled'), 20 | ('dead', 'Dead') 21 | ) 22 | 23 | class Lead(models.Model): 24 | title = models.CharField("Treatment Pronouns for the customer", 25 | max_length=64, blank=True, null=True) 26 | first_name = models.CharField(("First name"), max_length=255) 27 | last_name = models.CharField(("Last name"), max_length=255) 28 | email = models.EmailField() 29 | phone = models.CharField(max_length=20, null=True, blank=True) 30 | account = models.ForeignKey(Account, related_name='Leads', on_delete=models.CASCADE, blank=True, null=True) 31 | status = models.CharField("Status of Lead", max_length=255, 32 | blank=True, null=True, choices=LEAD_STATUS) 33 | source = models.CharField("Source of Lead", max_length=255, 34 | blank=True, null=True, choices=LEAD_SOURCE) 35 | address = models.CharField("Address", max_length=255, blank=True, null=True) 36 | 37 | website = models.CharField("Website", max_length=255, blank=True, null=True) 38 | description = models.TextField(blank=True, null=True) 39 | assigned_to = models.ManyToManyField(User, related_name='lead_assigned_users') 40 | account_name = models.CharField(max_length=255, null=True, blank=True) 41 | opportunity_amount = models.DecimalField("Opportunity Amount", decimal_places=2, max_digits=12, 42 | blank=True, null=True) 43 | createdBy = models.ForeignKey(User, related_name='lead_created_by', on_delete=models.CASCADE) 44 | createdOn = models.DateTimeField("Created on", auto_now_add=True) 45 | isActive = models.BooleanField(default=False) 46 | enquery_type = models.CharField(max_length=255, blank=True, null=True) 47 | 48 | def __str__(self): 49 | return self.first_name + self.last_name 50 | -------------------------------------------------------------------------------- /leads/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from .models import Lead 3 | 4 | class LeadSerializer(serializers.ModelSerializer): 5 | class Meta: 6 | model = Lead 7 | fields = "__all__" -------------------------------------------------------------------------------- /leads/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /leads/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from rest_framework import generics 3 | from .models import Lead 4 | from .serializers import LeadSerializer 5 | from rest_framework.permissions import IsAdminUser 6 | # Create your views here. 7 | 8 | class LeadListAPIView(generics.ListCreateAPIView): 9 | queryset = Lead.objects.all() 10 | serializer_class = LeadSerializer 11 | #permission_classes = (IsAdminUser,) -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "simplecrm.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /opportunities/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiediaries/django-crm/41b8f84a508f48b9d93e6cd33cbc2fe2707455cc/opportunities/__init__.py -------------------------------------------------------------------------------- /opportunities/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /opportunities/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class OpportunitiesConfig(AppConfig): 5 | name = 'opportunities' 6 | -------------------------------------------------------------------------------- /opportunities/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0.5 on 2018-05-04 22:27 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ('accounts', '0001_initial'), 15 | ('contacts', '0001_initial'), 16 | ] 17 | 18 | operations = [ 19 | migrations.CreateModel( 20 | name='Opportunity', 21 | fields=[ 22 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 23 | ('name', models.CharField(max_length=64)), 24 | ('stage', models.CharField(choices=[('QUALIFICATION', 'QUALIFICATION'), ('NEEDS ANALYSIS', 'NEEDS ANALYSIS'), ('VALUE PROPOSITION', 'VALUE PROPOSITION'), ('ID.DECISION MAKERS', 'ID.DECISION MAKERS'), ('PERCEPTION ANALYSIS', 'PERCEPTION ANALYSIS'), ('PROPOSAL/PRICE QUOTE', 'PROPOSAL/PRICE QUOTE'), ('NEGOTIATION/REVIEW', 'NEGOTIATION/REVIEW'), ('CLOSED WON', 'CLOSED WON'), ('CLOSED LOST', 'CLOSED LOST')], max_length=64)), 25 | ('amount', models.DecimalField(blank=True, decimal_places=2, max_digits=12, null=True, verbose_name='Opportunity Amount')), 26 | ('lead_source', models.CharField(blank=True, choices=[('NONE', 'NONE'), ('CALL', 'CALL'), ('EMAIL', ' EMAIL'), ('EXISTING CUSTOMER', 'EXISTING CUSTOMER'), ('PARTNER', 'PARTNER'), ('PUBLIC RELATIONS', 'PUBLIC RELATIONS'), ('CAMPAIGN', 'CAMPAIGN'), ('WEBSITE', 'WEBSITE'), ('OTHER', 'OTHER')], max_length=255, null=True, verbose_name='Source of Lead')), 27 | ('probability', models.IntegerField(blank=True, default=0, null=True)), 28 | ('closedOn', models.DateTimeField(blank=True, null=True)), 29 | ('description', models.TextField(blank=True, null=True)), 30 | ('createdOn', models.DateTimeField(auto_now_add=True, verbose_name='Created on')), 31 | ('isActive', models.BooleanField(default=False)), 32 | ('account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to='accounts.Account')), 33 | ('closedBy', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 34 | ('contacts', models.ManyToManyField(to='contacts.Contact')), 35 | ('createdBy', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opportunity_created_by', to=settings.AUTH_USER_MODEL)), 36 | ], 37 | ), 38 | ] 39 | -------------------------------------------------------------------------------- /opportunities/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiediaries/django-crm/41b8f84a508f48b9d93e6cd33cbc2fe2707455cc/opportunities/migrations/__init__.py -------------------------------------------------------------------------------- /opportunities/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import User 3 | from accounts.models import Account 4 | from contacts.models import Contact 5 | 6 | STAGES = ( 7 | ('QUALIFICATION', 'QUALIFICATION'), 8 | ('NEEDS ANALYSIS', 'NEEDS ANALYSIS'), 9 | ('VALUE PROPOSITION', 'VALUE PROPOSITION'), 10 | ('ID.DECISION MAKERS', 'ID.DECISION MAKERS'), 11 | ('PERCEPTION ANALYSIS', 'PERCEPTION ANALYSIS'), 12 | ('PROPOSAL/PRICE QUOTE', 'PROPOSAL/PRICE QUOTE'), 13 | ('NEGOTIATION/REVIEW', 'NEGOTIATION/REVIEW'), 14 | ('CLOSED WON', 'CLOSED WON'), 15 | ('CLOSED LOST', 'CLOSED LOST'), 16 | ) 17 | 18 | SOURCES = ( 19 | ('NONE', 'NONE'), 20 | ('CALL', 'CALL'), 21 | ('EMAIL', ' EMAIL'), 22 | ('EXISTING CUSTOMER', 'EXISTING CUSTOMER'), 23 | ('PARTNER', 'PARTNER'), 24 | ('PUBLIC RELATIONS', 'PUBLIC RELATIONS'), 25 | ('CAMPAIGN', 'CAMPAIGN'), 26 | ('WEBSITE', 'WEBSITE'), 27 | ('OTHER', 'OTHER'), 28 | ) 29 | 30 | 31 | 32 | TYPECHOICES = ( 33 | ('CUSTOMER', 'CUSTOMER'), 34 | ('INVESTOR', 'INVESTOR'), 35 | ('PARTNER', 'PARTNER'), 36 | ('RESELLER', 'RESELLER'), 37 | ) 38 | 39 | INDCHOICES = ( 40 | ('ADVERTISING', 'ADVERTISING'), 41 | ('AGRICULTURE', 'AGRICULTURE'), 42 | ('APPAREL & ACCESSORIES', 'APPAREL & ACCESSORIES'), 43 | ('AUTOMOTIVE', 'AUTOMOTIVE'), 44 | ('BANKING', 'BANKING'), 45 | ('BIOTECHNOLOGY', 'BIOTECHNOLOGY'), 46 | ('BUILDING MATERIALS & EQUIPMENT', 'BUILDING MATERIALS & EQUIPMENT'), 47 | ('CHEMICAL', 'CHEMICAL'), 48 | ('COMPUTER', 'COMPUTER'), 49 | ('EDUCATION', 'EDUCATION'), 50 | ('ELECTRONICS', 'ELECTRONICS'), 51 | ('ENERGY', 'ENERGY'), 52 | ('ENTERTAINMENT & LEISURE', 'ENTERTAINMENT & LEISURE'), 53 | ('FINANCE', 'FINANCE'), 54 | ('FOOD & BEVERAGE', 'FOOD & BEVERAGE'), 55 | ('GROCERY', 'GROCERY'), 56 | ('HEALTHCARE', 'HEALTHCARE'), 57 | ('INSURANCE', 'INSURANCE'), 58 | ('LEGAL', 'LEGAL'), 59 | ('MANUFACTURING', 'MANUFACTURING'), 60 | ('PUBLISHING', 'PUBLISHING'), 61 | ('REAL ESTATE', 'REAL ESTATE'), 62 | ('SERVICE', 'SERVICE'), 63 | ('SOFTWARE', 'SOFTWARE'), 64 | ('SPORTS', 'SPORTS'), 65 | ('TECHNOLOGY', 'TECHNOLOGY'), 66 | ('TELECOMMUNICATIONS', 'TELECOMMUNICATIONS'), 67 | ('TELEVISION', 'TELEVISION'), 68 | ('TRANSPORTATION', 'TRANSPORTATION'), 69 | ('VENTURE CAPITAL', 'VENTURE CAPITAL'), 70 | ) 71 | 72 | class Opportunity(models.Model): 73 | name = models.CharField(max_length=64) 74 | account = models.ForeignKey(Account, related_name='opportunities', on_delete=models.CASCADE, blank=True, null=True) 75 | stage = models.CharField( max_length=64, choices=STAGES) 76 | amount = models.DecimalField("Opportunity Amount", decimal_places=2, max_digits=12, blank=True, null=True) 77 | lead_source = models.CharField("Source of Lead", max_length=255, choices=SOURCES, blank=True, null=True) 78 | probability = models.IntegerField(default=0, blank=True, null=True) 79 | contacts = models.ManyToManyField(Contact) 80 | closedBy = models.ForeignKey(User, on_delete=models.CASCADE, null=True) 81 | closedOn = models.DateTimeField(blank=True, null=True) 82 | description = models.TextField(blank=True, null=True) 83 | createdBy = models.ForeignKey(User, related_name='opportunity_created_by', on_delete=models.CASCADE) 84 | createdOn = models.DateTimeField("Created on", auto_now_add=True) 85 | isActive = models.BooleanField(default=False) 86 | 87 | def __str__(self): 88 | return self.name 89 | 90 | 91 | -------------------------------------------------------------------------------- /opportunities/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from .models import Opportunity 3 | 4 | class OpportunitySerializer(serializers.ModelSerializer): 5 | class Meta: 6 | model = Opportunity 7 | fields = "__all__" -------------------------------------------------------------------------------- /opportunities/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /opportunities/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from rest_framework import generics 3 | from .models import Opportunity 4 | from .serializers import OpportunitySerializer 5 | from rest_framework.permissions import IsAdminUser 6 | # Create your views here. 7 | 8 | class OpportunityListAPIView(generics.ListCreateAPIView): 9 | queryset = Opportunity.objects.all() 10 | serializer_class = OpportunitySerializer 11 | #permission_classes = (IsAdminUser,) 12 | -------------------------------------------------------------------------------- /simplecrm/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techiediaries/django-crm/41b8f84a508f48b9d93e6cd33cbc2fe2707455cc/simplecrm/__init__.py -------------------------------------------------------------------------------- /simplecrm/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for simplecrm project. 3 | 4 | Generated by 'django-admin startproject' using Django 2.0.3. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.0/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/2.0/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = '77fy+^i(n=2)tq$0)&31d@uf3t+ge##$aclyla&lmr@lpinc1&' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | 'django.contrib.admin', 35 | 'django.contrib.auth', 36 | 'django.contrib.contenttypes', 37 | 'django.contrib.sessions', 38 | 'django.contrib.messages', 39 | 'django.contrib.staticfiles', 40 | 'accounts', 41 | 'leads', 42 | 'opportunities', 43 | 'contacts', 44 | 'rest_framework', 45 | 'corsheaders' 46 | ] 47 | 48 | MIDDLEWARE = [ 49 | 'django.middleware.security.SecurityMiddleware', 50 | 'corsheaders.middleware.CorsMiddleware', 51 | 'django.contrib.sessions.middleware.SessionMiddleware', 52 | 'django.middleware.common.CommonMiddleware', 53 | 'django.middleware.csrf.CsrfViewMiddleware', 54 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 55 | 'django.contrib.messages.middleware.MessageMiddleware', 56 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 57 | ] 58 | 59 | ROOT_URLCONF = 'simplecrm.urls' 60 | 61 | TEMPLATES = [ 62 | { 63 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 64 | 'DIRS': [], 65 | 'APP_DIRS': True, 66 | 'OPTIONS': { 67 | 'context_processors': [ 68 | 'django.template.context_processors.debug', 69 | 'django.template.context_processors.request', 70 | 'django.contrib.auth.context_processors.auth', 71 | 'django.contrib.messages.context_processors.messages', 72 | ], 73 | }, 74 | }, 75 | ] 76 | 77 | WSGI_APPLICATION = 'simplecrm.wsgi.application' 78 | 79 | 80 | # Database 81 | # https://docs.djangoproject.com/en/2.0/ref/settings/#databases 82 | 83 | DATABASES = { 84 | 'default': { 85 | 'ENGINE': 'django.db.backends.sqlite3', 86 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 87 | } 88 | } 89 | 90 | 91 | # Password validation 92 | # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators 93 | 94 | AUTH_PASSWORD_VALIDATORS = [ 95 | { 96 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 97 | }, 98 | { 99 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 100 | }, 101 | { 102 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 103 | }, 104 | { 105 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 106 | }, 107 | ] 108 | 109 | 110 | # Internationalization 111 | # https://docs.djangoproject.com/en/2.0/topics/i18n/ 112 | 113 | LANGUAGE_CODE = 'en-us' 114 | 115 | TIME_ZONE = 'UTC' 116 | 117 | USE_I18N = True 118 | 119 | USE_L10N = True 120 | 121 | USE_TZ = True 122 | 123 | 124 | # Static files (CSS, JavaScript, Images) 125 | # https://docs.djangoproject.com/en/2.0/howto/static-files/ 126 | 127 | STATIC_URL = '/static/' 128 | 129 | CORS_ORIGIN_WHITELIST = ( 130 | 'localhost:4200', 131 | ) -------------------------------------------------------------------------------- /simplecrm/urls.py: -------------------------------------------------------------------------------- 1 | """simplecrm URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.0/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path 18 | 19 | from accounts import views as aviews 20 | from leads import views as lviews 21 | from opportunities import views as oviews 22 | from contacts import views as cviews 23 | 24 | urlpatterns = [ 25 | path('admin/', admin.site.urls), 26 | path(r'accounts/', aviews.AccountListAPIView.as_view(), name='account-list'), 27 | path(r'leads/', lviews.LeadListAPIView.as_view(), name='lead-list'), 28 | path(r'opportunities/', oviews.OpportunityListAPIView.as_view(), name='opportunity-list'), 29 | path(r'contacts/', cviews.ContactListAPIView.as_view(), name='contact-list') 30 | ] 31 | -------------------------------------------------------------------------------- /simplecrm/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for simplecrm project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "simplecrm.settings") 15 | 16 | application = get_wsgi_application() 17 | --------------------------------------------------------------------------------