diff --git a/accounts/tests.py b/accounts/tests.py
index 67625c3f..2e9fd09b 100644
--- a/accounts/tests.py
+++ b/accounts/tests.py
@@ -1,23 +1,36 @@
from django.test import TestCase
from cases.models import Case
-from accounts.models import Account
-from common.models import User, Comment, Attachments
+from accounts.models import Account, Tags
+from common.models import User, Comment, Attachments, Address
+from django.urls import reverse
+from leads.models import Lead
+from contacts.models import Contact
+from django.core.files.uploadedfile import SimpleUploadedFile
class AccountCreateTest(object):
+
def setUp(self):
self.user = User.objects.create(
first_name="mike", username='mike', email='u@mp.com', role='ADMIN')
self.user.set_password('mike2293')
self.user.save()
+ self.user1 = User.objects.create(
+ first_name="mp",
+ username='mp',
+ email='mp@micropyramid.com',
+ role="USER")
+ self.user1.set_password('mp')
+ self.user1.save()
+
self.account = Account.objects.create(
name="mike", email="mike@micropyramid.com", phone="8333855552",
billing_address_line="", billing_street="KPHB",
billing_city="New York",
billing_state="usa", billing_postcode="500073",
billing_country="IN",
- website="www.mike.com", created_by=self.user,
+ website="www.mike.com", created_by=self.user, status="open",
industry="SOFTWARE", description="Yes.. Testing Done")
self.case = Case.objects.create(
name="raghu", case_type="Problem",
@@ -33,9 +46,40 @@ class AccountCreateTest(object):
created_by=self.user, account=self.account
)
self.client.login(email='u@mp.com', password='mike2293')
+ self.lead = Lead.objects.create(title="LeadCreation",
+ first_name="Alisa",
+ last_name="k",
+ email="Alisak1993@gmail.com",
+ address_line="",
+ street="Arcade enclave colony",
+ city="NewTown",
+ state="California",
+ postcode="5079",
+ country="AD",
+ website="www.gmail.com",
+ status="assigned",
+ source="Call",
+ opportunity_amount="700",
+ description="Iam an Lead",
+ created_by=self.user)
+ self.lead.assigned_to.add(self.user)
+ self.address = Address.objects.create(
+ street="5th phase",
+ city="Orlando",
+ state="Florida",
+ postcode=502279, country="AD")
+
+ self.contact = Contact.objects.create(
+ first_name="contact",
+ email="contact@gmail.com",
+ phone="12345",
+ address=self.address,
+ description="contact",
+ created_by=self.user)
class AccountsCreateTestCase(AccountCreateTest, TestCase):
+
def test_account_create_url(self):
response = self.client.get('/accounts/create/', {
'name': "mike", 'email': "mike@micropyramid.com",
@@ -87,12 +131,14 @@ class AccountsListTestCase(AccountCreateTest, TestCase):
class AccountsCountTestCase(AccountCreateTest, TestCase):
+
def test_accounts_list_count(self):
count = Account.objects.all().count()
self.assertEqual(count, 1)
class AccountsViewTestCase(AccountCreateTest, TestCase):
+
def test_accounts_view(self):
self.accounts = Account.objects.all()
response = self.client.get(
@@ -102,6 +148,7 @@ class AccountsViewTestCase(AccountCreateTest, TestCase):
class AccountsRemoveTestCase(AccountCreateTest, TestCase):
+
def test_accounts_remove(self):
response = self.client.get(
'/accounts/' + str(self.account.id) + '/delete/')
@@ -114,6 +161,7 @@ class AccountsRemoveTestCase(AccountCreateTest, TestCase):
class AccountsUpdateUrlTestCase(AccountCreateTest, TestCase):
+
def test_accounts_update(self):
response = self.client.get(
'/accounts/' + str(self.account.id) + '/edit/', {
@@ -187,14 +235,25 @@ class AccountModelTest(AccountCreateTest, TestCase):
class CommentTestCase(AccountCreateTest, TestCase):
+
def test_comment_add(self):
response = self.client.post(
- '/accounts/comment/add/', {'accountid': self.account.id})
+ '/accounts/comment/add/', {'accountid': self.account.id,
+ 'comment': 'comment'})
+ self.assertEqual(response.status_code, 200)
+
+ def test_comment_create(self):
+
+ response = self.client.post(
+ '/accounts/comment/add/', {'accountid': self.account.id,
+ 'comment': 'comment'})
self.assertEqual(response.status_code, 200)
def test_comment_edit(self):
+ self.client.login(email='mp@micropyramid.com', password='mp')
response = self.client.post(
- '/accounts/comment/edit/', {'commentid': self.comment.id})
+ '/accounts/comment/edit/', {'commentid': self.comment.id,
+ 'comment': 'comment'})
self.assertEqual(response.status_code, 200)
# def test_comment_valid(self):
@@ -210,16 +269,27 @@ class CommentTestCase(AccountCreateTest, TestCase):
'/accounts/comment/remove/', {'comment_id': self.comment.id})
self.assertEqual(response.status_code, 200)
+ def test_comment_deletion(self):
+ self.client.login(email='mp@micropyramid.com', password='mp')
+ response = self.client.post(
+ '/accounts/comment/remove/', {'comment_id': self.comment.id})
+ self.assertEqual(response.status_code, 200)
+
class AttachmentTestCase(AccountCreateTest, TestCase):
+
def test_attachment_add(self):
+ self.client.login(email='mp@micropyramid.com', password='mp')
response = self.client.post(
'/accounts/attachment/add/', {'accountid': self.account.id})
self.assertEqual(response.status_code, 200)
def test_attachment_valid(self):
+ upload_file = open('static/images/user.png', 'rb')
response = self.client.post(
- '/accounts/attachment/add/', {'accountid': self.account.id})
+ '/accounts/attachment/add/', {'accountid': self.account.id,
+ 'attachment': SimpleUploadedFile(
+ upload_file.name, upload_file.read())})
self.assertEqual(response.status_code, 200)
def test_attachment_delete(self):
@@ -227,3 +297,52 @@ class AttachmentTestCase(AccountCreateTest, TestCase):
'/accounts/attachment/remove/',
{'attachment_id': self.attachment.id})
self.assertEqual(response.status_code, 200)
+
+ def test_attachment_deletion(self):
+ self.client.login(email='mp@micropyramid.com', password='mp')
+ response = self.client.post(
+ '/accounts/attachment/remove/',
+ {'attachment_id': self.attachment.id})
+ self.assertEqual(response.status_code, 200)
+
+
+class TagCreateTest(object):
+
+ def setUp(self):
+ self.tag = Tags.objects.create(
+ name="tag", slug="tag1")
+
+
+class TagModelTest(TagCreateTest, TestCase):
+
+ def test_string_representation(self):
+ tag = Tags(name="tag", slug="tag1")
+ self.assertEqual(str(self.tag.name), tag.name)
+
+
+class TestCreateLeadPostView(AccountCreateTest, TestCase):
+
+ def test_create_lead_post_status(self):
+ upload_file = open('static/images/user.png', 'rb')
+ response = self.client.post(reverse(
+ 'accounts:new_account'), {"name": "mike",
+ "email": "mike@micropyramid.com",
+ "phone": "+91-833-385-5552",
+ "billing_address_line": "sddsv",
+ "billing_street": "KPHB",
+ "billing_city": "New York",
+ "billing_state": "usa",
+ "billing_postcode": "500073",
+ "billing_country": "IN",
+ "website": "www.mike.com",
+ "created_by": self.user,
+ "status": "open",
+ "industry": "SOFTWARE",
+ "description": "Yes.. Testing Done",
+ "lead": str(self.lead.id),
+ 'contacts': str(self.contact.id),
+ 'tags': 'tag1',
+ 'account_attachment': SimpleUploadedFile(
+ upload_file.name, upload_file.read())
+ })
+ self.assertEqual(response.status_code, 302)
diff --git a/cases/tests.py b/cases/tests.py
index 55b3dd89..d4ffb3cf 100644
--- a/cases/tests.py
+++ b/cases/tests.py
@@ -4,9 +4,12 @@ from contacts.models import Contact
from accounts.models import Account
from common.models import Address, Comment, Attachments
from common.models import User
+from django.contrib.contenttypes.models import ContentType
+from django.core.files.uploadedfile import SimpleUploadedFile
class CaseCreation(object):
+
def setUp(self):
self.address = Address.objects.create(
street="6th phase",
@@ -21,6 +24,13 @@ class CaseCreation(object):
role="ADMIN")
self.user.set_password('robert')
self.user.save()
+ self.user1 = User.objects.create(
+ first_name="mp",
+ username='mp',
+ email='mp@micropyramid.com',
+ role="USER")
+ self.user1.set_password('mp')
+ self.user1.save()
self.client.login(email='r@mp.com', password='robert')
self.client.login(email='r@mp.com', password='robert')
@@ -56,9 +66,12 @@ class CaseCreation(object):
attachment='image.png', case=self.case,
created_by=self.user, account=self.account
)
+ self.content_type = ContentType.objects.create(
+ app_label="cases1", model="case")
class CaseViewTestCase(CaseCreation, TestCase):
+
def test_list_cases(self):
self.cases = Case.objects.all()
response = self.client.get('/cases/list/')
@@ -78,12 +91,16 @@ class CaseViewTestCase(CaseCreation, TestCase):
class CaseCreationUrlTestCase(CaseCreation, TestCase):
+
def test_create_cases(self):
+ upload_file = open('static/images/user.png', 'rb')
response = self.client.post('/cases/create/', {
- 'name': 'new case', 'case_type': 'Problem',
- 'status': 'New',
- 'account': self.account, 'contacts': [self.contacts.id],
- 'priority': "Low", 'description': "something"
+ 'name': 'new case', 'closed_on': '2019-03-14',
+ 'status': 'New', 'priority': "Low",
+ 'created_by': self.user, "assigned_to": str(self.user.id),
+ 'contacts': str(self.contacts.id),
+ 'case_attachment': SimpleUploadedFile(
+ upload_file.name, upload_file.read())
})
self.assertEqual(response.status_code, 200)
@@ -99,8 +116,13 @@ class CaseCreationUrlTestCase(CaseCreation, TestCase):
# self.assertTemplateUsed(response, 'create_cases.html')
self.assertEqual(response.status_code, 200)
+ def test_create_case_get_request(self):
+ response = self.client.get('/cases/create/')
+ self.assertEqual(response.status_code, 200)
+
class CaseShowTestCase(CaseCreation, TestCase):
+
def test_show_case(self):
response = self.client.get('/cases/' + str(self.case.id) + '/view/')
self.assertEqual(response.status_code, 200)
@@ -116,6 +138,7 @@ class CaseShowTestCase(CaseCreation, TestCase):
class CaseRemoveTestCase(CaseCreation, TestCase):
+
def test_case_deletion_show_case(self):
response = self.client.get('/cases/' + str(self.case.id) + '/remove/')
self.assertEqual(response['location'], '/cases/list/')
@@ -128,15 +151,22 @@ class CaseRemoveTestCase(CaseCreation, TestCase):
class CaseUpdateTestCase(CaseCreation, TestCase):
+
def test_update_case_view(self):
response = self.client.get(
'/cases/' + str(self.case.id) + '/edit_case/')
self.assertEqual(response.status_code, 200)
def test_case_update(self):
- response = self.client.post(
- '/cases/' + str(self.case.id) + '/edit_case/',
- {'hiddenval': self.case.id})
+ upload_file = open('static/images/user.png', 'rb')
+ response = self.client.post('/cases/' + str(self.case.id) + '/edit_case/', {
+ 'name': 'new case', 'closed_on': '2019-03-14',
+ 'status': 'New', 'priority': "Low",
+ 'created_by': self.user, "assigned_to": str(self.user.id),
+ 'contacts': str(self.contacts.id),
+ 'case_attachment': SimpleUploadedFile(
+ upload_file.name, upload_file.read())
+ })
self.assertEqual(response.status_code, 200)
def test_case_update_html(self):
@@ -185,10 +215,17 @@ class CaseFormTestCase(CaseCreation, TestCase):
self.assertEqual(response.status_code, 200)
def test_comment_add(self):
+ self.client.login(email='mp@micropyramid.com', password='mp')
response = self.client.post(
'/cases/comment/add/', {'caseid': self.case.id})
self.assertEqual(response.status_code, 200)
+ def test_comment_form_valid(self):
+ response = self.client.post(
+ '/cases/comment/add/', {'caseid': self.case.id, 'comment': 'comment'})
+ self.assertEqual(response.status_code, 200)
+
+
def test_comment_edit(self):
response = self.client.post(
'/cases/comment/edit/', {'commentid': self.comment.id})
@@ -201,7 +238,18 @@ class CaseFormTestCase(CaseCreation, TestCase):
class AttachmentTestCase(CaseCreation, TestCase):
+
def test_attachment_add(self):
+ upload_file = open('static/images/user.png', 'rb')
+ response = self.client.post(
+ '/cases/attachment/add/', {'caseid': self.case.id,
+ 'attachment': SimpleUploadedFile(
+ upload_file.name, upload_file.read())
+ })
+ self.assertEqual(response.status_code, 200)
+
+ def test_attachment_creation(self):
+ self.client.login(email='mp@micropyramid.com', password='mp')
response = self.client.post(
'/cases/attachment/add/', {'caseid': self.case.id})
self.assertEqual(response.status_code, 200)
@@ -211,8 +259,15 @@ class AttachmentTestCase(CaseCreation, TestCase):
'/cases/attachment/remove/', {'attachment_id': self.attachment.id})
self.assertEqual(response.status_code, 200)
+ def test_attachment_deletion(self):
+ self.client.login(email='mp@micropyramid.com', password='mp')
+ response = self.client.post(
+ '/cases/attachment/remove/', {'attachment_id': self.attachment.id})
+ self.assertEqual(response.status_code, 200)
+
class SelectViewTestCase(CaseCreation, TestCase):
+
def test_select_contact(self):
response = self.client.get('/cases/select_contacts/')
self.assertEqual(response.status_code, 200)
diff --git a/common/tests.py b/common/tests.py
index e25ad61d..45845d33 100644
--- a/common/tests.py
+++ b/common/tests.py
@@ -1,11 +1,13 @@
from django.test import TestCase
from django.test import Client
-
+from django.urls import reverse
from common.models import User, Document
from common.forms import *
+from django.core.files.uploadedfile import SimpleUploadedFile
class ObjectsCreation(object):
+
def setUp(self):
self.client = Client()
# self.user = User.objects.create(first_name="admin",
@@ -33,13 +35,19 @@ class ObjectsCreation(object):
self.user.set_password('paul123')
self.user.save()
# self.user
- user_login = self.client.login(
+ self.client.login(
username='admin@micropyramid.com', password='admin123')
self.document = Document.objects.create(
title="abc", document_file="1.png", created_by=self.user)
+ self.comment = Comment.objects.create(
+ comment='testikd', user=self.user,
+ commented_by=self.user
+ )
+
class TestHomePage(ObjectsCreation, TestCase):
+
def test_home_page(self):
response = self.client.get('/')
self.assertEqual(response.status_code, 200)
@@ -80,6 +88,7 @@ class UserCreateTestCase(ObjectsCreation, TestCase):
class PasswordChangeTestCase(ObjectsCreation, TestCase):
+
def test_password_change(self):
self.client.login(username="admin@micropyramid.com",
password="admin123")
@@ -98,6 +107,14 @@ class PasswordChangeTestCase(ObjectsCreation, TestCase):
response = self.client.post(url, data)
self.assertEqual(response.status_code, 200)
+ def change_passsword_by_admin(self):
+ print(self.user, "madhu", self.user.role)
+ response = self.client.post(reverse('common:change_passsword_by_admin'), {
+ 'useer_id': self.user.id,
+ 'new_passwoord': "admin123"
+ })
+ self.assertEqual(response.status_code, 302)
+
class ForgotPasswordViewTestCase(ObjectsCreation, TestCase):
@@ -109,7 +126,8 @@ class ForgotPasswordViewTestCase(ObjectsCreation, TestCase):
class LoginViewTestCase(ObjectsCreation, TestCase):
# user2 = User.objects.create(first_name="paul", username='paul', email='paul@micropyramid.com',
- # is_staff=True, is_admin=True, is_superuser=True, is_active=False)
+ # is_staff=True, is_admin=True, is_superuser=True, is_active=False)
+
def test_login_post(self):
self.client.logout()
data = {"email": "admin@micropyramid.com", "password": "admin123"}
@@ -147,6 +165,7 @@ class LoginViewTestCase(ObjectsCreation, TestCase):
class UserTestCase(ObjectsCreation, TestCase):
+
def test_user_create_url(self):
response = self.client.get('/users/create/', {
'first_name': 'micheal',
@@ -188,6 +207,7 @@ class UserListTestCase(ObjectsCreation, TestCase):
class UserRemoveTestCase(ObjectsCreation, TestCase):
+
def test_users_remove(self):
response = self.client.get('/users/' + str(self.user.id) + '/delete/')
self.assertEqual(response['location'], '/users/list/')
@@ -199,6 +219,7 @@ class UserRemoveTestCase(ObjectsCreation, TestCase):
class UserUpdateTestCase(ObjectsCreation, TestCase):
+
def test_users_update(self):
response = self.client.get('/users/' + str(self.user.id) + '/edit/', {
'first_name': "admin",
@@ -239,6 +260,7 @@ class UserUpdateTestCase(ObjectsCreation, TestCase):
class ProfileViewTestCase(ObjectsCreation, TestCase):
+
def test_profile_view(self):
url = "/profile/"
response = self.client.get(url)
@@ -254,6 +276,7 @@ class ProfileViewTestCase(ObjectsCreation, TestCase):
class UserDetailView(ObjectsCreation, TestCase):
+
def test_user_detail(self):
url = "/users/" + str(self.user.id) + "/view/"
response = self.client.get(url)
@@ -261,6 +284,7 @@ class UserDetailView(ObjectsCreation, TestCase):
class DocumentDetailView(ObjectsCreation, TestCase):
+
def test_document_detail(self):
url = "/documents/" + str(self.document.id) + "/view/"
repsonse = self.client.get(url)
@@ -271,12 +295,8 @@ class DocumentDetailView(ObjectsCreation, TestCase):
class CreateCommentFile(TestCase):
+
def test_invalid_user_form(self):
- fields = ['email',
- 'first_name',
- 'last_name',
- 'username', 'role',
- 'profile_pic']
user1 = User.objects.create(username='robert',
first_name='robert',
last_name='clark',
@@ -295,3 +315,81 @@ class CreateCommentFile(TestCase):
self.assertEqual(len(userr.password), 3)
self.assertFalse(form.is_valid())
# self.assertTrue(form.)
+
+
+class CommentTestCase(ObjectsCreation, TestCase):
+
+ def test_comment_add(self):
+ response = self.client.post(
+ '/comment/add/', {'userid': self.user.id})
+ self.assertEqual(response.status_code, 200)
+
+ def test_comment_edit(self):
+ response = self.client.post(reverse('common:edit_comment',
+ kwargs={'pk': self.comment.id}))
+ self.assertEqual(response.status_code, 200)
+ resp = self.client.post(reverse('common:edit_comment',
+ kwargs={'pk': self.comment.id}), {'comment': 'hello123'})
+ self.assertEqual(resp.status_code, 200)
+
+ def test_comment_delete(self):
+ response = self.client.post(
+ '/comment/remove/', {'comment_id': self.comment.id})
+ self.assertEqual(response.status_code, 200)
+
+ def test_form_valid(self):
+ response = self.client.post(
+ '/comment/add/', {'userid': self.user.id,
+ 'comment': 'hello'})
+ self.assertEqual(response.status_code, 200)
+
+
+class DocumentTestCase(ObjectsCreation, TestCase):
+
+ def test_document_add(self):
+ response = self.client.post(
+ '/documents/create/')
+ self.assertEqual(response.status_code, 200)
+
+ def test_document_create(self):
+ response = self.client.post(
+ '/documents/create/')
+ self.assertEqual(response.status_code, 200)
+
+ def test_document_edit(self):
+ upload_file = open('static/images/user.png', 'rb')
+ data = {'title': "doc",
+ 'created_by': self.user,
+ 'document_file': SimpleUploadedFile(
+ upload_file.name, upload_file.read()),
+ 'status': 'active',
+ 'shared_to': str(self.user.id)}
+ response = self.client.get(reverse('common:edit_doc',
+ kwargs={'pk': self.document.id}), data)
+ self.assertEqual(response.status_code, 200)
+
+ def test_document_valid(self):
+ upload_file = open('static/images/user.png', 'rb')
+ response = self.client.post(
+ '/documents/create/', {'title': "doc",
+ 'created_by': self.user,
+ 'document_file': SimpleUploadedFile(
+ upload_file.name, upload_file.read()),
+ 'status': 'active',
+ 'shared_to': str(self.user.id)})
+ self.assertEqual(response.status_code, 200)
+
+ def test_document_delete(self):
+ response = self.client.get(reverse('common:remove_doc',
+ kwargs={'pk': self.document.id}))
+ self.assertEqual(response.status_code, 302)
+
+ def test_document_list_view(self):
+ response = self.client.get(reverse('common:doc_list'))
+ self.assertEqual(response.status_code, 200)
+ response = self.client.post(reverse('common:doc_list'), {
+ 'doc_name': 'doc',
+ 'status': 'active',
+ "shared_to": str(self.user.id)
+ })
+ self.assertEqual(response.status_code, 200)
diff --git a/contacts/tests.py b/contacts/tests.py
index 2bb1b43a..c601a50e 100644
--- a/contacts/tests.py
+++ b/contacts/tests.py
@@ -4,9 +4,13 @@ from common.models import Address, User, Comment, Attachments
from cases.models import Case
from django.test import Client
from django.urls import reverse
+from django.core.files.uploadedfile import SimpleUploadedFile
+from contacts.forms import ContactAttachmentForm
+from accounts.models import Account
class ContactObjectsCreation(object):
+
def setUp(self):
self.client = Client()
self.user = User.objects.create(
@@ -50,6 +54,7 @@ class ContactObjectsCreation(object):
class ContactObjectsCreation_Count(ContactObjectsCreation, TestCase):
+
def test_contact_object_creation(self):
c = Contact.objects.count()
con = Contact.objects.filter(id=self.contact.id)
@@ -77,6 +82,7 @@ class ContactViewsTestCase(ContactObjectsCreation, TestCase):
self.assertTemplateUsed(response, 'contacts.html')
def test_contacts_create(self):
+ upload_file = open('static/images/user.png', 'rb')
response = self.client.post('/contacts/create/', {
'first_name': 'contact',
'last_name': 'george',
@@ -84,7 +90,45 @@ class ContactViewsTestCase(ContactObjectsCreation, TestCase):
'phone': '+917898901234',
'address': self.address.id,
'description': 'contact',
- 'created_by': self.user})
+ 'created_by': self.user,
+ 'assigned_to': str(self.user.id),
+ 'contact_attachment': SimpleUploadedFile(
+ upload_file.name, upload_file.read())
+ })
+ self.assertEqual(response.status_code, 302)
+
+ def test_contact_create(self):
+ upload_file = open('static/images/user.png', 'rb')
+ response = self.client.post('/contacts/create/', {
+ 'first_name': 'contact',
+ 'last_name': 'george',
+ 'email': 'meg@gmail.com',
+ 'phone': '+917898901234',
+ 'address': self.address.id,
+ 'description': 'contact',
+ 'created_by': self.user,
+ 'assigned_to': str(self.user.id),
+ 'contact_attachment': SimpleUploadedFile(
+ upload_file.name, upload_file.read())
+ })
+ self.assertEqual(response.status_code, 302)
+
+ def test_update_contact(self):
+ upload_file = open('static/images/user.png', 'rb')
+ url = '/contacts/' + str(self.contact.id) + '/edit/'
+ data = {
+ 'first_name': 'contact',
+ 'last_name': 'george',
+ 'email': 'meg@gmail.com',
+ 'phone': '+917898901234',
+ 'address': self.address.id,
+ 'description': 'contact',
+ 'created_by': self.user,
+ 'assigned_to': str(self.user.id),
+ 'contact_attachment': SimpleUploadedFile(
+ upload_file.name, upload_file.read())
+ }
+ response = self.client.post(url, data)
self.assertEqual(response.status_code, 302)
def test_contacts_create_html(self):
@@ -166,6 +210,7 @@ class ContactsListTestCase(ContactObjectsCreation, TestCase):
class CommentTestCase(ContactObjectsCreation, TestCase):
+
def test_comment_add(self):
response = self.client.post(
'/contacts/comment/add/', {'contactid': self.contact.id})
@@ -199,14 +244,18 @@ class CommentTestCase(ContactObjectsCreation, TestCase):
class AttachmentTestCase(ContactObjectsCreation, TestCase):
+
def test_attachment_add(self):
response = self.client.post(
'/contacts/attachment/add/', {'contactid': self.contact.id})
self.assertEqual(response.status_code, 200)
def test_attachment_valid(self):
+ upload_file = open('static/images/user.png', 'rb')
response = self.client.post(
- '/contacts/attachment/add/', {'contactid': self.contact.id})
+ '/contacts/attachment/add/', {'contactid': self.contact.id,
+ 'attachment': SimpleUploadedFile(
+ upload_file.name, upload_file.read())})
self.assertEqual(response.status_code, 200)
def test_attachment_delete(self):
diff --git a/crm/settings.py b/crm/settings.py
index f91608ee..e9046b62 100644
--- a/crm/settings.py
+++ b/crm/settings.py
@@ -1,4 +1,5 @@
import os
+from celery.schedules import crontab
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@@ -107,7 +108,7 @@ AUTH_PASSWORD_VALIDATORS = [
LANGUAGE_CODE = 'en-us'
-TIME_ZONE = 'Asia/Calcutta'
+TIME_ZONE = 'Asia/Kolkata'
USE_I18N = True
@@ -219,6 +220,21 @@ DEFAULT_FROM_EMAIL = 'no-reply@django-crm.micropyramid.com'
CELERY_BROKER_URL = 'redis://localhost:6379'
CELERY_RESULT_BACKEND = 'redis://localhost:6379'
+CELERY_BEAT_SCHEDULE = {
+ "runs-campaign-for-every-thiry-minutes": {
+ "task": "marketing.tasks.run_all_campaigns",
+ "schedule": crontab(minute=30, hour='*')
+ },
+ "runs-campaign-for-every-five-minutes": {
+ "task": "marketing.tasks.list_all_bounces_unsubscribes",
+ "schedule": crontab(minute='*/5')
+ },
+ "runs-scheduled-campaigns-for-every-one-hour": {
+ "task": "marketing.tasks.send_scheduled_campaigns",
+ "schedule": crontab(hour='*/1')
+ },
+}
+
MAIL_SENDER = 'AMAZON'
INACTIVE_MAIL_SENDER = 'MANDRILL'
@@ -236,6 +252,8 @@ MANDRILL_API_KEY = os.getenv('MANDRILL_API_KEY', '')
ADMIN_EMAIL = "admin@micropyramid.com"
+URL_FOR_LINKS = "http://djangocrm.com"
+
try:
from .dev_settings import *
except ImportError:
diff --git a/crm/urls.py b/crm/urls.py
index 02026995..c0a054ba 100644
--- a/crm/urls.py
+++ b/crm/urls.py
@@ -1,3 +1,5 @@
+from django.conf import settings
+from django.conf.urls.static import static
from django.contrib.auth import views
from django.urls import include, path
from common.views import handler404, handler500
@@ -20,5 +22,9 @@ urlpatterns = [
]
+if settings.DEBUG:
+ urlpatterns = urlpatterns + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
+
+
handler404 = handler404
handler500 = handler500
diff --git a/leads/forms.py b/leads/forms.py
index b9a154ce..9ab63ef8 100644
--- a/leads/forms.py
+++ b/leads/forms.py
@@ -15,6 +15,9 @@ class LeadForm(forms.ModelForm):
self.fields['email'].required = True
self.fields['assigned_to'].queryset = assigned_users
self.fields['assigned_to'].required = False
+ self.fields['first_name'].required = False
+ self.fields['last_name'].required = False
+ self.fields['title'].required = True
for key, value in self.fields.items():
if key == 'phone':
value.widget.attrs['placeholder'] =\
diff --git a/leads/migrations/0008_auto_20190315_1503.py b/leads/migrations/0008_auto_20190315_1503.py
new file mode 100644
index 00000000..7e195a7c
--- /dev/null
+++ b/leads/migrations/0008_auto_20190315_1503.py
@@ -0,0 +1,29 @@
+# Generated by Django 2.1.7 on 2019-03-15 09:33
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('leads', '0007_auto_20190306_1226'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='lead',
+ name='first_name',
+ field=models.CharField(max_length=255, null=True, verbose_name='First name'),
+ ),
+ migrations.AlterField(
+ model_name='lead',
+ name='last_name',
+ field=models.CharField(max_length=255, null=True, verbose_name='Last name'),
+ ),
+ migrations.AlterField(
+ model_name='lead',
+ name='title',
+ field=models.CharField(default='title', max_length=64, verbose_name='Title'),
+ preserve_default=False,
+ ),
+ ]
diff --git a/leads/models.py b/leads/models.py
index 0763756b..4acfd971 100644
--- a/leads/models.py
+++ b/leads/models.py
@@ -13,9 +13,9 @@ from contacts.models import Contact
class Lead(models.Model):
title = models.CharField(
pgettext_lazy("Treatment Pronouns for the customer",
- "Title"), max_length=64, blank=True, null=True)
- first_name = models.CharField(("First name"), max_length=255)
- last_name = models.CharField(("Last name"), max_length=255)
+ "Title"), max_length=64)
+ first_name = models.CharField(("First name"), null=True, max_length=255)
+ last_name = models.CharField(("Last name"), null=True, max_length=255)
email = models.EmailField(null=True, blank=True)
phone = PhoneNumberField(null=True, blank=True)
status = models.CharField(
diff --git a/leads/templates/leads.html b/leads/templates/leads.html
index fd892f5d..a0153845 100644
--- a/leads/templates/leads.html
+++ b/leads/templates/leads.html
@@ -113,7 +113,7 @@
{% if open_leads|length > 0 %}
| ID |
- Name |
+ Title |
Created By |
Source |
Status |
@@ -133,7 +133,8 @@
{% for lead in open_leads %}
| {{ forloop.counter }} |
- {{ lead.first_name }} {{ lead.last_name }} |
+
+ {{ lead.title }} |
{% if lead.created_by.profile_pic %}
{% thumbnail lead.created_by.profile_pic "40x40" crop="center" as im %}
@@ -207,7 +208,7 @@
{% if close_leads|length > 0 %}
|
| ID |
- Name |
+ Title |
Source |
Status |
Assigned User |
@@ -226,7 +227,8 @@
{% for lead in close_leads %}
| {{ forloop.counter }} |
- {{ lead.first_name }} {{ lead.last_name }} |
+
+ {{ lead.title }} |
{{ lead.source }} |
{{ lead.get_status_display }} |
diff --git a/leads/templates/view_leads.html b/leads/templates/view_leads.html
index 343f9aa7..e2e08c3c 100644
--- a/leads/templates/view_leads.html
+++ b/leads/templates/view_leads.html
@@ -37,11 +37,12 @@
-
{% if lead_record.account_name %}
diff --git a/leads/tests.py b/leads/tests.py
index 06ef0200..27410df4 100644
--- a/leads/tests.py
+++ b/leads/tests.py
@@ -1,13 +1,16 @@
from django.test import TestCase, Client
from cases.models import Case
from leads.models import Lead
-from common.models import User, Comment, Attachments
+from common.models import User, Comment, Attachments, APISettings
from accounts.models import Account
from leads.tasks import *
from leads.forms import *
+from django.urls import reverse
+from django.core.files.uploadedfile import SimpleUploadedFile
class TestLeadModel(object):
+
def setUp(self):
self.client = Client()
@@ -16,6 +19,14 @@ class TestLeadModel(object):
self.user.set_password('jorge2293')
self.user.save()
+ self.user1 = User.objects.create(
+ first_name="mp",
+ username='mp',
+ email='mp@micropyramid.com',
+ role="USER")
+ self.user1.set_password('mp')
+ self.user1.save()
+
self.client.login(username='j@mp.com', password='jorge2293')
self.account = Account.objects.create(name="account",
@@ -36,7 +47,7 @@ class TestLeadModel(object):
first_name="Alisa",
last_name="k",
email="Alisak1993@gmail.com",
- address_line="",
+ address_line="hyd",
street="Arcade enclave colony",
city="NewTown",
state="California",
@@ -47,7 +58,10 @@ class TestLeadModel(object):
source="Call",
opportunity_amount="700",
description="Iam an Lead",
- created_by=self.user)
+ created_by=self.user,
+ account_name="account",
+ phone="+91-123-456-7890")
+ self.lead.assigned_to.add(self.user)
self.case = Case.objects.create(
name="Rose", case_type="Problem",
status="New",
@@ -60,9 +74,12 @@ class TestLeadModel(object):
attachment='image.png',
case=self.case, created_by=self.user,
account=self.account)
+ self.api_seetings = APISettings.objects.create(
+ title="api", apikey="api", created_by=self.user)
class LeadsPostrequestTestCase(TestLeadModel, TestCase):
+
def test_valid_postrequesttestcase_date(self):
data = {'title': 'LeadCreation', 'first_name': "micky",
'last_name': "Alisa", 'email': "Alisamicky1993@gmail.com",
@@ -95,6 +112,7 @@ class LeadsPostrequestTestCase(TestLeadModel, TestCase):
class LeadsCreateUrlTestCase(TestLeadModel, TestCase):
+
def test_leads_create_url(self):
response = self.client.post('/leads/create/', {
'title': 'LeadCreation',
@@ -128,8 +146,21 @@ class LeadsCreateUrlTestCase(TestLeadModel, TestCase):
# self.assertTemplateUsed(response, 'create_lead.html')
self.assertEqual(response.status_code, 200)
+ def test_leads_create_with_status_converted(self):
+ response = self.client.post('/leads/create/', {
+ 'title': 'LeadCreation', 'name': "micky",
+ 'email': "Alisamicky1993@gmail.com", 'account': self.account,
+ 'address_line': "", 'account_name': 'account1',
+ 'street': "Arcade enclave colony", 'city': "NewTown",
+ 'state': "California", 'postcode': "579", 'country': "AD",
+ 'website': "www.gmail.com", 'status': "converted",
+ "source": "Call", 'opportunity_amount': "700",
+ 'description': "Iam an Lead", 'created_by': self.user})
+ self.assertEqual(response.status_code, 200)
+
class LeadsEditUrlTestCase(TestLeadModel, TestCase):
+
def test_leads_editurl(self):
response = self.client.get('/leads/' + str(self.lead.id) + '/edit/')
self.assertEqual(response.status_code, 200)
@@ -177,6 +208,7 @@ class LeadListTestCase(TestLeadModel, TestCase):
class GetLeadsViewTestCase(TestLeadModel, TestCase):
+
def test_get_lead(self):
url = '/leads/get/list/'
response = self.client.get(url)
@@ -215,6 +247,7 @@ class UpdateLeadTestCase(TestLeadModel, TestCase):
class LeadDetailTestCase(TestLeadModel, TestCase):
+
def test_lead_detail(self):
url = '/leads/' + str(self.lead.id) + '/view/'
response = self.client.get(url, {'status': ''})
@@ -222,12 +255,25 @@ class LeadDetailTestCase(TestLeadModel, TestCase):
class CommentTestCase(TestLeadModel, TestCase):
+
def test_comment_add(self):
+ self.client.login(email='mp@micropyramid.com', password='mp')
response = self.client.post(
'/leads/comment/add/', {'leadid': self.lead.id})
self.assertEqual(response.status_code, 200)
+ def test_comment_create(self):
+ response = self.client.post(
+ '/leads/comment/add/', {'leadid': self.lead.id, 'comment': "comment"})
+ self.assertEqual(response.status_code, 200)
+
def test_comment_edit(self):
+ response = self.client.post(
+ '/leads/comment/edit/', {'commentid': self.comment.id, 'comment': "comment"})
+ self.assertEqual(response.status_code, 200)
+
+ def test_comment_update(self):
+ self.client.login(email='mp@micropyramid.com', password='mp')
response = self.client.post(
'/leads/comment/edit/', {'commentid': self.comment.id})
self.assertEqual(response.status_code, 200)
@@ -237,9 +283,17 @@ class CommentTestCase(TestLeadModel, TestCase):
'/leads/comment/remove/', {'comment_id': self.comment.id})
self.assertEqual(response.status_code, 200)
+ def test_comment_deletion(self):
+ self.client.login(email='mp@micropyramid.com', password='mp')
+ response = self.client.post(
+ '/leads/comment/remove/', {'comment_id': self.comment.id})
+ self.assertEqual(response.status_code, 200)
+
class AttachmentTestCase(TestLeadModel, TestCase):
+
def test_attachment_add(self):
+ self.client.login(email='mp@micropyramid.com', password='mp')
response = self.client.post(
'/leads/attachment/add/', {'leadid': self.lead.id})
self.assertEqual(response.status_code, 200)
@@ -249,8 +303,23 @@ class AttachmentTestCase(TestLeadModel, TestCase):
'/leads/attachment/remove/', {'attachment_id': self.attachment.id})
self.assertEqual(response.status_code, 200)
+ def test_attachment_deletion(self):
+ self.client.login(email='mp@micropyramid.com', password='mp')
+ response = self.client.post(
+ '/leads/attachment/remove/', {'attachment_id': self.attachment.id})
+ self.assertEqual(response.status_code, 200)
+
+ def test_attachment_valid(self):
+ upload_file = open('static/images/user.png', 'rb')
+ response = self.client.post(
+ '/leads/attachment/add/', {'leadid': self.lead.id,
+ 'attachment': SimpleUploadedFile(
+ upload_file.name, upload_file.read())})
+ self.assertEqual(response.status_code, 200)
+
class TestTemplates(TestLeadModel, TestCase):
+
def test_lead_list_view(self):
resp = self.client.post('/leads/list/', {'name': 'trevor',
'tag': "123",
@@ -266,6 +335,83 @@ class TestTemplates(TestLeadModel, TestCase):
class TestConvertLeadView(TestLeadModel, TestCase):
+
def test_get_fun(self):
resp = self.client.get('/leads/' + str(self.lead.id) + '/convert/')
self.assertEqual(resp.status_code, 302)
+
+
+class TestCreateLeadPostView(TestLeadModel, TestCase):
+
+ def test_create_lead_post_status(self):
+ upload_file = open('static/images/user.png', 'rb')
+ response = self.client.post(reverse(
+ 'leads:add_lead'), {'first_name': 'm',
+ 'last_name': 's',
+ "created_by": self.user,
+ 'status': 'converted',
+ 'description': 'wgrgre',
+ 'website': 'www.mike.com',
+ 'phone': '+91-123-456-7890',
+ 'email': 'a@gmail.com',
+ 'account_name': 'account',
+ 'address_line': self.lead.address_line,
+ 'street': self.lead.street,
+ 'city': self.lead.city,
+ 'state': self.lead.state,
+ 'postcode': self.lead.postcode,
+ 'country': self.lead.country,
+ 'lead_attachment': SimpleUploadedFile(
+ upload_file.name, upload_file.read()),
+ 'assigned_to': str(self.user.id),
+ 'tags': 'tag'
+ })
+ self.assertEqual(response.status_code, 200)
+
+ def test_create_lead_get_request(self):
+ response = self.client.get(reverse('leads:add_lead'))
+ self.assertEqual(response.status_code, 200)
+
+ def test_update_lead_post_status(self):
+ upload_file = open('static/images/user.png', 'rb')
+ response = self.client.post('/leads/' + str(self.lead.id) + '/edit/',
+ {'first_name': 'm',
+ 'last_name': 's',
+ "created_by": self.user,
+ 'status': 'converted',
+ 'description': 'wgrgre',
+ 'website': 'www.mike.com',
+ 'phone': '+91-123-456-7890',
+ 'email': 'a@gmail.com',
+ 'account_name': 'account',
+ 'address_line': self.lead.address_line,
+ 'street': self.lead.street,
+ 'city': self.lead.city,
+ 'state': self.lead.state,
+ 'postcode': self.lead.postcode,
+ 'country': self.lead.country,
+ 'lead_attachment': SimpleUploadedFile(
+ upload_file.name, upload_file.read()),
+ 'assigned_to': str(self.user.id),
+ 'tags': 'tag'
+ })
+ self.assertEqual(response.status_code, 200)
+
+ def test_lead_convert(self):
+ response = self.client.get('/leads/' + str(self.lead.id) + '/convert/')
+ self.assertEqual(response.status_code, 302)
+
+
+class TestLeadDetailView(TestLeadModel, TestCase):
+
+ def test_lead_detail_view(self):
+ response = self.client.get(
+ reverse('leads:view_lead', kwargs={'pk': self.lead.id}))
+ self.assertEqual(response.status_code, 200)
+
+
+class TestLeadFromSite(TestLeadModel, TestCase):
+
+ def create_lead_from_site(self):
+ response = self.client.post('/leads/create/from-site/', {'apikey': self.api_seetings.apikey})
+ self.assertEqual(response.status_code, 200)
diff --git a/marketing/forms.py b/marketing/forms.py
index 0327bf8b..bc9e0762 100644
--- a/marketing/forms.py
+++ b/marketing/forms.py
@@ -10,9 +10,12 @@ from marketing.models import (
EmailTemplate, Campaign, Tag
)
+email_regex = '^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$'
+
def csv_doc_validate(document):
temp_row = []
+ invalid_row = []
reader = csv.reader((document.read().decode("utf-8")).splitlines())
# csv_headers = ["first name", "last name", "email"]
csv_headers = ["first name", "email"]
@@ -20,6 +23,7 @@ def csv_doc_validate(document):
required_headers = ["first name", "email"]
for y_index, row in enumerate(reader):
each = {}
+ invalid_each = {}
if y_index == 0:
csv_headers = [header_name.lower()
for header_name in row if header_name]
@@ -40,15 +44,23 @@ def csv_doc_validate(document):
continue
if csv_headers[x_index] in required_headers:
if not cell_value:
- message = 'Missing required value %s for row %s' % (
- csv_headers[x_index], y_index + 1)
- return {"error": True, "message": message}
+ # message = 'Missing required value %s for row %s' % (
+ # csv_headers[x_index], y_index + 1)
+ # return {"error": True, "message": message}
+ invalid_each[csv_headers[x_index]] = cell_value
+ else:
+ if csv_headers[x_index] == "email":
+ if re.match(email_regex, cell_value) is None:
+ invalid_each[csv_headers[x_index]] = cell_value
each[csv_headers[x_index]] = cell_value
- temp_row.append(each)
- return {"error": False, "validated_rows": temp_row}
+ if invalid_each:
+ invalid_row.append(each)
+ else:
+ temp_row.append(each)
+ return {"error": False, "validated_rows": temp_row, "invalid_rows": invalid_row}
-def get_validated_rows(wb, sheet_name, validated_rows):
+def get_validated_rows(wb, sheet_name, validated_rows, invalid_rows):
# headers = ["first name", "last name", "email"]
# required_headers = ["first name", "last name", "email"]
headers = ["first name", "email"]
@@ -68,6 +80,7 @@ def get_validated_rows(wb, sheet_name, validated_rows):
continue
else:
temp_row = []
+ invalid_row = []
for x_index, cell in enumerate(row):
try:
headers[x_index]
@@ -75,29 +88,28 @@ def get_validated_rows(wb, sheet_name, validated_rows):
continue
if headers[x_index] in required_headers:
if not cell.value:
- message = 'Missing required \
- value %s for row %s in sheet %s'\
- % (headers[x_index], y_index + 1, sheet_name)
- return {"error": True, "message": message}
- # elif x_index == 0:
- # cell_value = is_valid_date_format(cell.value)
- # if not cell_value:
- # message = 'Invalid date format(format:yyyy-mm-dd) \
- # %s for row %s in sheet %s' % (headers[x_index], y_index + 1, sheet_name)
- # return {"error": True, "message": message}
+ # message = 'Missing required \
+ # value %s for row %s in sheet %s'\
+ # % (headers[x_index], y_index + 1, sheet_name)
+ # return {"error": True, "message": message}
+ invalid_row.append(headers[x_index])
temp_row.append(cell.value)
- if len(temp_row) >= len(required_headers):
- validated_rows.append(temp_row)
- return validated_rows
+ if len(invalid_row) > 0:
+ invalid_rows.append(temp_row)
+ else:
+ if len(temp_row) >= len(required_headers):
+ validated_rows.append(temp_row)
+ return validated_rows, invalid_rows
def xls_doc_validate(document):
wb = openpyxl.load_workbook(document)
sheets = wb.get_sheet_names()
validated_rows = []
+ invalid_rows = []
for sheet_name in sheets:
- get_validated_rows(wb, sheet_name, validated_rows)
- return {"error": False, "validated_rows": validated_rows}
+ validated_rows, invalid_rows = get_validated_rows(wb, sheet_name, validated_rows, invalid_rows)
+ return {"error": False, "validated_rows": validated_rows, "invalid_rows": invalid_rows}
def import_document_validator(document):
@@ -141,7 +153,8 @@ class ContactListForm(forms.ModelForm):
if data.get("error"):
raise forms.ValidationError(data.get("message"))
else:
- self.validated_rows = data.get("validated_rows")
+ self.validated_rows = data.get("validated_rows", [])
+ self.invalid_rows = data.get("invalid_rows", [])
return document
def clean_tags(self):
@@ -265,7 +278,7 @@ class SendCampaignForm(forms.ModelForm):
class Meta:
model = Campaign
- fields = ['title', 'subject', 'html', 'email_template']
+ fields = ['title', 'subject', 'html', 'email_template', 'attachment']
def __init__(self, *args, **kwargs):
super(SendCampaignForm, self).__init__(*args, **kwargs)
@@ -278,11 +291,11 @@ class SendCampaignForm(forms.ModelForm):
def clean_contact_list(self):
contact_list = self.cleaned_data.get("contact_list")
if not contact_list or contact_list == '[]' or \
- json.loads(contact_list) == []:
+ contact_list == []:
raise forms.ValidationError(
"Please choose any of the Contact List")
else:
- for each in json.loads(contact_list):
+ for each in contact_list:
if not ContactList.objects.filter(id=each).first():
raise forms.ValidationError(
"Please choose a valid Contact List")
diff --git a/marketing/migrations/0004_auto_20190315_1443.py b/marketing/migrations/0004_auto_20190315_1443.py
new file mode 100644
index 00000000..afdbea8b
--- /dev/null
+++ b/marketing/migrations/0004_auto_20190315_1443.py
@@ -0,0 +1,24 @@
+# Generated by Django 2.1.7 on 2019-03-15 09:13
+
+import django.core.validators
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('marketing', '0003_failedcontact'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='contact',
+ name='contact_number',
+ field=models.CharField(blank=True, max_length=20, null=True, validators=[django.core.validators.RegexValidator(message="Phone number must be entered in the format: '+999999999'. Up to 20 digits allowed.", regex='^\\+?1?\\d{9,15}$')]),
+ ),
+ migrations.AlterField(
+ model_name='failedcontact',
+ name='contact_number',
+ field=models.CharField(blank=True, max_length=20, null=True, validators=[django.core.validators.RegexValidator(message="Phone number must be entered in the format: '+999999999'. Up to 20 digits allowed.", regex='^\\+?1?\\d{9,15}$')]),
+ ),
+ ]
diff --git a/marketing/migrations/0005_campaign_timezone.py b/marketing/migrations/0005_campaign_timezone.py
new file mode 100644
index 00000000..31de46df
--- /dev/null
+++ b/marketing/migrations/0005_campaign_timezone.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.1.7 on 2019-03-18 07:00
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('marketing', '0004_auto_20190315_1443'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='campaign',
+ name='timezone',
+ field=models.CharField(default='UTC', max_length=100),
+ ),
+ ]
diff --git a/marketing/migrations/0006_campaign_attachment.py b/marketing/migrations/0006_campaign_attachment.py
new file mode 100644
index 00000000..d8cad5c9
--- /dev/null
+++ b/marketing/migrations/0006_campaign_attachment.py
@@ -0,0 +1,19 @@
+# Generated by Django 2.1.7 on 2019-03-19 10:29
+
+from django.db import migrations, models
+import marketing.models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('marketing', '0005_campaign_timezone'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='campaign',
+ name='attachment',
+ field=models.FileField(blank=True, max_length=1000, null=True, upload_to=marketing.models.get_campaign_attachment_path),
+ ),
+ ]
diff --git a/marketing/models.py b/marketing/models.py
index fea77fd0..87ed96eb 100644
--- a/marketing/models.py
+++ b/marketing/models.py
@@ -1,11 +1,14 @@
+import os
from datetime import datetime, timedelta
from django.db import models
from django.utils.timesince import timesince
from django.utils.translation import ugettext_lazy as _
from django.core.validators import RegexValidator
+from django.dispatch import receiver
from django.db.models import Sum
from django.template.defaultfilters import slugify
from common.models import User
+from common.utils import convert_to_custom_timezone
class Tag(models.Model):
@@ -150,6 +153,13 @@ class FailedContact(models.Model):
return self.email
+def get_campaign_attachment_path(self, filename):
+ file_split = filename.split('.')
+ file_extension = file_split[-1]
+ path = "%s_%s" % (file_split[0], str(datetime.now()))
+ return "campaigns/attachment/" + slugify(path) + "." + file_extension
+
+
class Campaign(models.Model):
STATUS_CHOICES = (
('Scheduled', 'Scheduled'),
@@ -170,6 +180,7 @@ class Campaign(models.Model):
email_template = models.ForeignKey(
EmailTemplate, blank=True, null=True, on_delete=models.SET_NULL)
schedule_date_time = models.DateTimeField(blank=True, null=True)
+ timezone = models.CharField(max_length=100, default='UTC')
reply_to_email = models.EmailField(blank=True, null=True)
subject = models.CharField(max_length=5000)
html = models.TextField()
@@ -182,6 +193,8 @@ class Campaign(models.Model):
bounced = models.IntegerField(default='0')
status = models.CharField(
default="Preparing", choices=STATUS_CHOICES, max_length=20)
+ attachment = models.FileField(
+ max_length=1000, upload_to=get_campaign_attachment_path, blank=True, null=True)
@property
def no_of_unsubscribers(self):
@@ -209,6 +222,27 @@ class Campaign(models.Model):
def created_on_format(self):
return self.created_on.strftime('%b %d, %Y %I:%M %p')
+ @property
+ def sent_on_format(self):
+ if self.schedule_date_time:
+ c_schedule_date_time = convert_to_custom_timezone(self.schedule_date_time, self.timezone)
+ return c_schedule_date_time.strftime('%b %d, %Y %I:%M %p')
+ else:
+ c_created_on = convert_to_custom_timezone(self.created_on, self.timezone)
+ return c_created_on.strftime('%b %d, %Y %I:%M %p')
+
+
+@receiver(models.signals.pre_delete, sender=Campaign)
+def comment_attachments_delete(sender, instance, **kwargs):
+ attachment = instance.attachment
+ if attachment:
+ try:
+ if os.path.isfile(attachment.path):
+ os.remove(attachment.path)
+ except Exception:
+ return False
+ return True
+
class Link(models.Model):
campaign = models.ForeignKey(
diff --git a/marketing/tasks.py b/marketing/tasks.py
index 8be0e0fc..7341e1ab 100644
--- a/marketing/tasks.py
+++ b/marketing/tasks.py
@@ -2,12 +2,13 @@ import datetime
import hashlib
import pytz
import requests
+from mimetypes import MimeTypes
from celery.task import task
from django.conf import settings
from django.core.mail import EmailMessage
from django.template import Template, Context
from common.utils import convert_to_custom_timezone
-from marketing.models import Contact, ContactList, Campaign, CampaignLog
+from marketing.models import Contact, FailedContact, ContactList, Campaign, CampaignLog
@task
@@ -26,7 +27,7 @@ def campaign_click(request):
@task
-def upload_csv_file(data, user, contact_lists):
+def upload_csv_file(data, invalid_data, user, contact_lists):
for each in data:
contact = Contact.objects.filter(email=each['email']).first()
if not contact:
@@ -45,6 +46,24 @@ def upload_csv_file(data, user, contact_lists):
for contact_list in contact_lists:
contact.contact_list.add(ContactList.objects.get(id=int(contact_list)))
+ for each in invalid_data:
+ contact = FailedContact.objects.filter(email=each['email']).first()
+ if not contact:
+ contact = FailedContact.objects.create(
+ email=each['email'], created_by_id=user,
+ name=each['first name'])
+ if each.get('company name', None):
+ contact.company_name = each['company name']
+ if each.get('last name', None):
+ contact.last_name = each['last name']
+ if each.get('city', None):
+ contact.city = each['city']
+ if each.get("state", None):
+ contact.state = each['state']
+ contact.save()
+ for contact_list in contact_lists:
+ contact.contact_list.add(ContactList.objects.get(id=int(contact_list)))
+
def send_campaign_mail(subject, content, from_email, to_email, bcc, reply_to, attachments):
msg = EmailMessage(
@@ -76,13 +95,18 @@ def get_campaign_message_id(campaign):
def run_campaign(campaign):
try:
campaign = Campaign.objects.get(id=campaign)
+ attachments = []
+ if campaign.attachment:
+ file_path = campaign.attachment.path
+ file_name = file_path.split("/")[-1]
+ content = open(file_path, 'rb').read()
+ mime = MimeTypes()
+ mime_type = mime.guess_type(file_path)
+ attachments.append((file_name, content, mime_type[0]))
subject = campaign.subject
- # project_settings = Settings.objects.filter().first()
- contacts = []
- for each_list in campaign.contact_lists.all():
- contacts = Contact.objects.filter(contact_list__in=[each_list])
- # contacts = campaign.contacts.filter(Q(is_bounced=False) | Q(is_unsubscribed=False)).distinct()
+ contacts = Contact.objects.filter(
+ contact_list__in=[each_list for each_list in campaign.contact_lists.all()])
default_html = campaign.html_processed
for each_contact in contacts:
html = default_html
@@ -94,18 +118,15 @@ def run_campaign(campaign):
message_id = get_campaign_message_id(campaign_log)
campaign_log.message_id = message_id
campaign_log.save()
- domain_name = settings.SUBDOMAIN_NAME + '.' + project_settings.domain if project_settings else ''
- # domain_name = 'micro.peeljobs.com'
+ domain_name = 'django-crm.com'
if campaign.from_email is not None:
from_email = campaign.from_email
else:
from_email = campaign.created_by.email
reply_to_email = str(from_email) + ' <' + str(message_id + '@' + domain_name + '') + '>'
if not (each_contact.is_bounced or each_contact.is_unsubscribed):
- # link = '  + '/) '
- domain_url = '%s%s' % (settings.SCHEME, settings.HOST_URL)
- link = '  '
names_dict = {'company_name': each_contact.company_name if each_contact.company_name else '',
'last_name': each_contact.last_name if each_contact.last_name else '',
@@ -117,13 +138,9 @@ def run_campaign(campaign):
html = Template(html).render(Context(names_dict))
mail_html = html + link
from_email = str(campaign.from_name) + "<" + str(campaign.from_email) + '>'
- # text_content = re.sub(r'<(.*?)>', '', html)
- # ReplyMail.objects.create(campaign_log=campaign_log,
- # reply_from=campaign.created_by.email,
- # text=text_content,
- # sent_on=datetime.datetime.now())
+ to_email = [each_contact.email]
send_campaign_mail(
- subject, mail_html, from_email, [each_contact.email], [], [reply_to_email], [])
+ subject, mail_html, from_email, to_email, [], [reply_to_email], attachments)
except Exception as e:
print (e)
pass
@@ -161,14 +178,16 @@ def send_scheduled_campaigns():
from datetime import datetime
campaigns = Campaign.objects.filter(schedule_date_time__isnull=False)
for each in campaigns:
- sent_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- sent_time = datetime.strptime(sent_time, '%Y-%m-%d %H:%M:%S')
- local_tz = pytz.timezone('UTC')
- schedule_date_time_hour = str(each.schedule_date_time.time()).replace(':00:00', '')
+ schedule_date_time = each.schedule_date_time
+
+ sent_time = datetime.now().strftime('%Y-%m-%d %H:%M')
+ sent_time = datetime.strptime(sent_time, '%Y-%m-%d %H:%M')
+ local_tz = pytz.timezone(settings.TIME_ZONE)
sent_time = local_tz.localize(sent_time)
- sent_time = convert_to_custom_timezone(sent_time, each.timezone)
+ sent_time = convert_to_custom_timezone(sent_time, each.timezone, to_utc=True)
+
if (
str(each.schedule_date_time.date()) == str(sent_time.date()) and
- str(schedule_date_time_hour) == str(sent_time.hour)
+ str(schedule_date_time.hour) == str(sent_time.hour)
):
run_campaign(each)
diff --git a/marketing/tests.py b/marketing/tests.py
index d5df681b..1db06eb1 100644
--- a/marketing/tests.py
+++ b/marketing/tests.py
@@ -27,7 +27,7 @@ class TestTemplates(TestMarketingModel, TestCase):
url4 = '/m/cl/lists/'
url5 = '/m/cl/list/new/'
url6 = '/m/cl/list/cnew/'
- url7 = '/m/cl/list/detail/'
+ # url7 = '/m/cl/list/detail/'
url8 = '/m/et/list/'
url9 = '/m/et/new/'
# url10 = '/m/et/edit/'
@@ -42,7 +42,7 @@ class TestTemplates(TestMarketingModel, TestCase):
resp4 = self.client.get(url4)
resp5 = self.client.get(url5)
resp6 = self.client.get(url6)
- resp7 = self.client.get(url7)
+ # resp7 = self.client.get(url7)
resp8 = self.client.get(url8)
resp9 = self.client.get(url9)
# resp10 = self.client.get(url10)
@@ -57,7 +57,7 @@ class TestTemplates(TestMarketingModel, TestCase):
self.assertEqual(resp4.status_code, 200)
self.assertEqual(resp5.status_code, 200)
self.assertEqual(resp6.status_code, 200)
- self.assertEqual(resp7.status_code, 200)
+ # self.assertEqual(resp7.status_code, 200)
self.assertEqual(resp8.status_code, 200)
self.assertEqual(resp9.status_code, 200)
# self.assertEqual(resp10.status_code, 200)
diff --git a/marketing/urls.py b/marketing/urls.py
index 86adfebd..8da6f9e0 100644
--- a/marketing/urls.py
+++ b/marketing/urls.py
@@ -3,7 +3,8 @@ from .views import (
dashboard, contact_lists, contacts_list, contact_list_new, contacts_list_new, contact_list_detail, edit_contact,
email_template_list, email_template_new, email_template_edit, email_template_delete,
email_template_detail, campaign_list, campaign_new, campaign_edit, campaign_details, campaign_delete,
- edit_contact_list, delete_contact_list
+ edit_contact_list, delete_contact_list, failed_contact_list_detail, failed_contact_list_download_delete,
+ campaign_link_click, campaign_open
)
app_name = 'marketing'
@@ -15,10 +16,13 @@ urlpatterns = [
path('cl/edit_contact/', edit_contact, name='edit_contact'),
path('cl/lists/', contacts_list, name='contacts_list'),
path('cl/list/new/', contact_list_new, name='contact_list_new'),
- path('cl/list/edit/ /', edit_contact_list, name='edit_contact_list'),
- path('cl/list/delete//', delete_contact_list, name='delete_contact_list'),
path('cl/list/cnew/', contacts_list_new, name='contacts_list_new'),
- path('cl/list/detail/', contact_list_detail, name='contact_list_detail'),
+ path('cl/list//detail/', contact_list_detail, name='contact_list_detail'),
+ path('cl/list//failed/', failed_contact_list_detail, name='failed_contact_list_detail'),
+ path('cl/list//failed/download/',
+ failed_contact_list_download_delete, name='failed_contact_list_download_delete'),
+ path('cl/list//edit/', edit_contact_list, name='edit_contact_list'),
+ path('cl/list//delete/', delete_contact_list, name='delete_contact_list'),
path('et/list/', email_template_list, name='email_template_list'),
path('et/new/', email_template_new, name='email_template_new'),
@@ -30,5 +34,7 @@ urlpatterns = [
path('cm/new/', campaign_new, name='campaign_new'),
path('cm//edit/', campaign_edit, name='campaign_edit'),
path('cm//details/', campaign_details, name='campaign_details'),
- path('cm//delete/', campaign_delete, name='campaign_delete')
+ path('cm//delete/', campaign_delete, name='campaign_delete'),
+ path('cm/link//e//', campaign_link_click, name='campaign_link_click'),
+ path('cm/track-email//contact//', campaign_open, name='campaign_open'),
]
diff --git a/marketing/views.py b/marketing/views.py
index 8d829d42..95295d78 100644
--- a/marketing/views.py
+++ b/marketing/views.py
@@ -1,19 +1,23 @@
+import csv
import json
import pytz
import lxml
import lxml.html
from lxml.cssselect import CSSSelector
-from django.conf import Settings
+from datetime import datetime as ddatetime
+from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.db.models import Q
from django.http.response import (JsonResponse,
HttpResponse, HttpResponseRedirect)
-from django.shortcuts import render, get_object_or_404
+from django.shortcuts import render, get_object_or_404, redirect
from django.urls import reverse_lazy, reverse
from common import status
+from common.utils import convert_to_custom_timezone
from marketing.models import (
- Tag, ContactList, Contact, EmailTemplate, Campaign, CampaignLog, Link
+ Tag, ContactList, Contact, EmailTemplate, Campaign, CampaignLog, Link, CampaignLinkClick,
+ CampaignOpen
)
from marketing.forms import ContactListForm, ContactForm, EmailTemplateForm, SendCampaignForm
from marketing.tasks import upload_csv_file, run_campaign
@@ -97,7 +101,7 @@ def contact_list_new(request):
instance.tags.add(tag)
if request.FILES.get('contacts_file'):
upload_csv_file.delay(
- form.validated_rows, request.user.id, [instance.id])
+ form.validated_rows, form.invalid_rows, request.user.id, [instance.id])
return JsonResponse({'error': False,
'data': form.data},
@@ -144,7 +148,7 @@ def edit_contact_list(request, pk):
instance.tags.add(tag)
if request.FILES.get('contacts_file'):
upload_csv_file.delay(
- form.validated_rows, request.user.id, [instance.id])
+ form.validated_rows, form.invalid_rows, request.user.id, [instance.id])
return JsonResponse({'error': False,
'data': form.data}, status=status.HTTP_200_OK)
@@ -215,8 +219,38 @@ def edit_contact(request):
@login_required(login_url='/login')
-def contact_list_detail(request):
- return render(request, 'marketing/lists/detail.html')
+def contact_list_detail(request, pk):
+ contact_list = get_object_or_404(ContactList, pk=pk)
+ contacts_list = contact_list.contacts.all()
+ data = {'contact_list': contact_list, "contacts_list": contacts_list}
+ return render(request, 'marketing/lists/detail.html', data)
+
+
+@login_required(login_url='/login')
+def failed_contact_list_detail(request, pk):
+ contact_list = get_object_or_404(ContactList, pk=pk)
+ failed_contacts_list = contact_list.failed_contacts.all()
+ data = {'contact_list': contact_list, "failed_contacts_list": failed_contacts_list}
+ return render(request, 'marketing/lists/failed_detail.html', data)
+
+
+@login_required(login_url='/login')
+def failed_contact_list_download_delete(request, pk):
+ contact_list = get_object_or_404(ContactList, pk=pk)
+ failed_contacts_list = contact_list.failed_contacts.all()
+ if failed_contacts_list.count() > 0:
+ response = HttpResponse(content_type='text/csv')
+ response['Content-Disposition'] = 'attachment; filename="failed_contacts.csv"'
+ writer = csv.writer(response)
+ writer.writerow(["company name", "email", "first name", "last name", "city", "state"])
+
+ for contact in failed_contacts_list:
+ writer.writerow([
+ contact.company_name, contact.email, contact.name, contact.last_name, contact.city, contact.state])
+ failed_contacts_list.delete()
+ return response
+ else:
+ return HttpResponseRedirect(reverse('marketing:contact_lists', kwargs={"pk": pk}))
@login_required(login_url='/login')
@@ -336,23 +370,25 @@ def campaign_new(request):
# contact_list__id__in=json.loads(request.GET.get('contact_list'))).distinct()
data = {
- 'contact_lists': contact_lists, 'email_templates': email_templates, "timezones": TIMEZONE_CHOICES}
+ 'contact_lists': contact_lists, 'email_templates': email_templates,
+ "timezones": TIMEZONE_CHOICES, "settings_timezone": settings.TIME_ZONE}
# return JsonResponse(data, status=status.HTTP_200_OK)
return render(request, 'marketing/campaign/new.html', data)
else:
- print ("request.POST", request.POST)
- form = SendCampaignForm(request.POST)
+ form = SendCampaignForm(request.POST, request.FILES)
if form.is_valid():
instance = form.save(commit=False)
instance.created_by = request.user
- if request.POST['from_email']:
+ if request.POST.get('from_email'):
instance.from_email = request.POST['from_email']
- if request.POST['from_name']:
+ if request.POST.get('from_name'):
instance.from_name = request.POST['from_name']
- if request.POST['reply_to_email']:
+ if request.POST.get('reply_to_email'):
instance.reply_to_email = request.POST['reply_to_email']
+ # if request.FILES.get('attachment'):
+ # instance.attachment = request.FILES.get('attachment')
instance.save()
- for each in json.loads(request.POST['contact_list']):
+ for each in request.POST.getlist('contact_list'):
instance.contact_lists.add(ContactList.objects.get(id=each))
# contacts = Contact.objects.filter(contact_list__in=json.loads(request.POST['contact_list'])).distinct()
# for each_contact in contacts:
@@ -373,33 +409,31 @@ def campaign_new(request):
links = set(llist)
# Replace Links with new One
- domain_url = '%s://%s' % (request.scheme, request.META['HTTP_HOST'])
+ # domain_url = '%s://%s' % (request.scheme, request.META['HTTP_HOST'])
+ domain_url = settings.URL_FOR_LINKS
if Link.objects.filter(campaign_id=camp.id):
Link.objects.filter(campaign_id=camp.id).delete()
for l in links:
link = Link.objects.create(campaign_id=camp.id, original=l)
html = html.replace(
- 'href="' + l + '"', 'href="' + domain_url + '/a/' + str(link.id) + '/e/{{email_id}}"')
+ 'href="' + l + '"', 'href="' + domain_url + '/m/cm/link/' + str(link.id) + '/e/{{email_id}}"')
camp.html_processed = html
camp.sent_status = "scheduled"
camp.save()
- if request.POST['schedule_later'] == 'false':
- run_campaign.delay(instance.id)
- else:
+ if request.POST.get('schedule_later', None) == 'true':
schedule_date_time = request.POST.get('schedule_date_time', '')
- # user_timezone = request.POST.get('timezone', '')
- # if user_timezone and schedule_date_time:
- # print ("schedule_date_time", schedule_date_time)
- # print ("timezone", user_timezone)
- # start_time_object = ddatetime.strptime(schedule_date_time, '%Y-%m-%d %H:%M:%S')
- # schedule_date_time = convert_to_custom_timezone(start_time_object, user_timezone, to_utc=True)
- # print ("After", schedule_date_time)
+ user_timezone = request.POST.get('timezone', '')
+ if user_timezone and schedule_date_time:
+ start_time_object = ddatetime.strptime(schedule_date_time, '%Y-%m-%d %H:%M')
+ schedule_date_time = convert_to_custom_timezone(start_time_object, user_timezone, to_utc=True)
instance.schedule_date_time = schedule_date_time
- # instance.timezone = request.POST['timezone']
- instance.save()
+ instance.timezone = user_timezone
+ instance.save()
+ else:
+ run_campaign.delay(instance.id)
- return JsonResponse({'error': True, 'data': form.data}, status=status.HTTP_201_CREATED)
+ return JsonResponse({'error': False, 'data': form.data}, status=status.HTTP_201_CREATED)
return JsonResponse({'error': True, 'errors': form.errors}, status=status.HTTP_200_OK)
@@ -409,10 +443,186 @@ def campaign_edit(request):
@login_required(login_url='/login')
-def campaign_details(request):
- return render(request, 'marketing/campaign/details.html')
+def campaign_details(request, pk):
+ try:
+ campaign = Campaign.objects.get(pk=pk)
+ except Campaign.DoesNotExist:
+ return redirect(reverse('marketing:campaign_list'))
+
+ contact_lists = campaign.contact_lists.all()
+ if (request.user.is_admin or request.user.is_superuser):
+ contact_lists = contact_lists
+ else:
+ contact_lists = contact_lists.filter(
+ is_public=True, created_by=request.user)
+
+ contacts = Contact.objects.filter(contact_list__in=contact_lists)
+ contact_list_ids = campaign.contact_lists.all().values_list('id', flat=True)
+
+ contacts = Contact.objects.filter(contact_list__id__in=contact_list_ids)
+
+ all_contacts = contacts
+ bounced_contacts = contacts.filter(is_bounced=True)
+ unsubscribe_contacts = contacts.filter(
+ is_unsubscribed=True)
+ read_contacts = campaign.marketing_links.filter(Q(clicks__gt=0))
+ # read_contacts =
+ sent_contacts = contacts.exclude(
+ Q(is_bounced=True) | Q(is_unsubscribed=True))
+ if request.POST:
+ contacts = contacts.filter(Q(name__icontains=request.POST['search']))
+
+ tab = request.GET.get('tab', 'contacts')
+ per_page = request.GET.get("per_page", 10)
+ page = request.GET.get('page', 1)
+
+ contacts_paginator = Paginator(contacts.order_by('id'), per_page)
+ if (tab == "contacts"):
+ page = page
+ else:
+ page = 1
+ try:
+ contacts = contacts_paginator.page(page)
+ except PageNotAnInteger:
+ contacts = contacts_paginator.page(1)
+ except EmptyPage:
+ contacts = contacts_paginator.page(contacts_paginator.num_pages)
+
+ unsubscribe_contacts_paginator = Paginator(unsubscribe_contacts.order_by('id'), per_page)
+ if (tab == "unsubscribe_contacts"):
+ page = page
+ else:
+ page = 1
+
+ try:
+ unsubscribe_contacts = unsubscribe_contacts_paginator.page(page)
+ except PageNotAnInteger:
+ unsubscribe_contacts = unsubscribe_contacts_paginator.page(1)
+ except EmptyPage:
+ unsubscribe_contacts = unsubscribe_contacts_paginator.page(unsubscribe_contacts_paginator.num_pages)
+
+ bounced_contacts_paginator = Paginator(bounced_contacts.order_by('id'), per_page)
+ if (tab == "bounced_contacts"):
+ page = page
+ else:
+ page = 1
+
+ try:
+ bounced_contacts = bounced_contacts_paginator.page(page)
+ except PageNotAnInteger:
+ bounced_contacts = bounced_contacts_paginator.page(1)
+ except EmptyPage:
+ bounced_contacts = bounced_contacts_paginator.page(bounced_contacts_paginator.num_pages)
+
+ sent_contacts_paginator = Paginator(sent_contacts.order_by('id'), per_page)
+ if (tab == "sent_contacts"):
+ page = page
+ else:
+ page = 1
+
+ try:
+ sent_contacts = sent_contacts_paginator.page(page)
+ except PageNotAnInteger:
+ sent_contacts = sent_contacts_paginator.page(1)
+ except EmptyPage:
+ sent_contacts = sent_contacts_paginator.page(sent_contacts_paginator.num_pages)
+
+ all_contacts_paginator = Paginator(all_contacts.order_by('id'), per_page)
+ if (tab == "all_contacts"):
+ page = page
+ else:
+ page = 1
+
+ try:
+ all_contacts = all_contacts_paginator.page(page)
+ except PageNotAnInteger:
+ all_contacts = all_contacts_paginator.page(1)
+ except EmptyPage:
+ all_contacts = all_contacts_paginator.page(all_contacts_paginator.num_pages)
+
+ read_contacts_paginator = Paginator(read_contacts.order_by('id'), per_page)
+ if (tab == "read_contacts"):
+ page = page
+ else:
+ page = 1
+
+ try:
+ read_contacts = read_contacts_paginator.page(page)
+ except PageNotAnInteger:
+ read_contacts = read_contacts_paginator.page(1)
+ except EmptyPage:
+ read_contacts = read_contacts_paginator.page(read_contacts_paginator.num_pages)
+
+ data = {'contact_lists': contact_lists, "campaign": campaign,
+ "contacts": contacts, 'unsubscribe_contacts': unsubscribe_contacts,
+ 'bounced_contacts': bounced_contacts, 'read_contacts': read_contacts,
+ 'sent_contacts': sent_contacts, 'all_contacts': all_contacts, 'tab': tab}
+
+ return render(request, 'marketing/campaign/details.html', data)
@login_required(login_url='/login')
-def campaign_delete(request):
- return render(request, 'marketing/campaign/details.html')
+def campaign_delete(request, pk):
+ try:
+ campaign = Campaign.objects.get(id=pk)
+ campaign.delete()
+ redirect_url = reverse('marketing:campaign_list')
+ except Campaign.DoesNotExist:
+ redirect_url = reverse('marketing:campaign_list')
+ return redirect(redirect_url)
+
+
+def campaign_link_click(request, link_id, email_id):
+ x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
+
+ if x_forwarded_for:
+ ipaddress = x_forwarded_for.split(',')[-1].strip()
+ else:
+ ipaddress = request.META.get('REMOTE_ADDR')
+
+ link = Link.objects.filter(id=link_id).first()
+ contact = Contact.objects.filter(id=email_id).first()
+ if link and contact:
+ campaign_link_click = CampaignLinkClick.objects.filter(
+ link=link, campaign=link.campaign, contact=contact).first()
+ if not campaign_link_click:
+ campaign_link_click = CampaignLinkClick.objects.create(
+ link=link, campaign=link.campaign, contact=contact, ip_address=ipaddress)
+ link.unique += 1
+ else:
+ campaign_link_click.ip_address = ipaddress
+ link.clicks += 1
+ link.save()
+ campaign_link_click.save()
+ url = link.original
+ else:
+ url = settings.URL_FOR_LINKS
+ return redirect(url)
+
+
+def campaign_open(request, campaign_log_id, email_id):
+ x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
+
+ if x_forwarded_for:
+ ipaddress = x_forwarded_for.split(',')[-1].strip()
+ else:
+ ipaddress = request.META.get('REMOTE_ADDR')
+
+ campaign_log = CampaignLog.objects.filter(id=campaign_log_id).first()
+ contact = Contact.objects.filter(id=email_id).first()
+ image_data = settings.STATIC_URL + 'images/'
+ image_data = open(settings.STATIC_ROOT + '/images/company.png', 'rb').read()
+ if campaign_log and contact:
+ campaign_open = CampaignOpen.objects.filter(
+ campaign=campaign_log.campaign, contact=contact).first()
+ if not campaign_open:
+ campaign_open = CampaignOpen.objects.create(
+ campaign=campaign_log.campaign, contact=contact, ip_address=ipaddress)
+ campaign_log.campaign.opens_unique += 1
+ else:
+ campaign_open.ip_address = ipaddress
+ campaign_log.campaign.opens += 1
+ campaign_log.campaign.status = "Sent"
+ campaign_log.campaign.save()
+ campaign_open.save()
+ return HttpResponse(image_data, content_type="image/png")
diff --git a/opportunity/tests.py b/opportunity/tests.py
index 6ec6a51c..325ae2cf 100644
--- a/opportunity/tests.py
+++ b/opportunity/tests.py
@@ -4,12 +4,14 @@ from accounts.models import Account
from contacts.models import Contact
from common.models import User, Comment, Attachments, Address
from cases.models import Case
+from django.core.files.uploadedfile import SimpleUploadedFile
# Create your tests here.
class OpportunityModel(object):
+
def setUp(self):
self.user = User.objects.create(
@@ -47,6 +49,7 @@ class OpportunityModel(object):
closed_on="2016-05-04",
description="hgfdxc",
created_by=self.user)
+ self.opportunity.assigned_to.add(self.user)
self.case = Case.objects.create(
name="raghu", case_type="Problem", status="New", account=self.account,
priority="Low", description="something",
@@ -58,6 +61,7 @@ class OpportunityModel(object):
class OpportunityCreateTestCase(OpportunityModel, TestCase):
+
def test_opportunity_create(self):
response = self.client.get('/opportunities/create/', {
'name': "meghan", 'amount': "478",
@@ -67,8 +71,14 @@ class OpportunityCreateTestCase(OpportunityModel, TestCase):
self.assertEqual(response.status_code, 200)
def test_opportunity_create_post(self):
+ upload_file = open('static/images/user.png', 'rb')
url = '/opportunities/create/'
- data = {'name': "micky", 'amount': "500", 'stage': "CLOSED WON"}
+ data = {'name': "micky", 'amount': "500", 'stage': "CLOSED WON",
+ 'assigned_to': str(self.user.id),
+ 'contacts': str(self.contacts.id),
+ 'tags': 'tag',
+ 'oppurtunity_attachment': SimpleUploadedFile(
+ upload_file.name, upload_file.read())}
response = self.client.post(url, data)
# self.assertEqual(response.status_code, 302)
self.assertEqual(response.status_code, 200)
@@ -113,16 +123,24 @@ class EditOpportunityTestCase(OpportunityModel, TestCase):
'stage': "negotiation/review",
'lead_source': "Call", 'probability': "58",
'closed_on': "2016-05-04", 'description': "hgfdxc"})
- resp = self.client.post( '/opportunities/' + str(self.opportunity.id) + '/edit/', **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'})
+ resp = self.client.post('/opportunities/' + str(self.opportunity.id) +
+ '/edit/', **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'})
self.assertEqual(resp.status_code, 200)
- resp1 = self.client.post( '/opportunities/create/', **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'})
+ resp1 = self.client.post(
+ '/opportunities/create/', **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'})
self.assertEqual(resp1.status_code, 200)
def test_update_opportunity(self):
+ upload_file = open('static/images/user.png', 'rb')
url = '/opportunities/' + str(self.opportunity.id) + '/edit/'
data = {
'name': "meghan", 'amount': "478", 'stage': "QUALIFICATION",
- 'probability': "58", 'closed_on': "2016-05-04", 'description': "hgfdxc"}
+ 'probability': "58", 'closed_on': "2016-05-04",
+ 'description': "hgfdxc",
+ 'tags': 'tag', 'assigned_to': str(self.user.id),
+ 'contacts': str(self.contacts.id),
+ 'oppurtunity_attachment': SimpleUploadedFile(
+ upload_file.name, upload_file.read())}
response = self.client.post(url, data)
# self.assertEqual(response.status_code, 302)
self.assertEqual(response.status_code, 200)
@@ -137,6 +155,7 @@ class EditOpportunityTestCase(OpportunityModel, TestCase):
class OpportunityListView(OpportunityModel, TestCase):
+
def test_opportunity_list(self):
self.opportunity = Opportunity.objects.all()
response = self.client.get('/opportunities/list/')
@@ -164,6 +183,7 @@ class OpportunityListView(OpportunityModel, TestCase):
class ContactGetViewTestCase(OpportunityModel, TestCase):
+
def test_get_contact(self):
url = '/opportunities/contacts/'
response = self.client.get(url)
@@ -173,6 +193,7 @@ class ContactGetViewTestCase(OpportunityModel, TestCase):
class CommentTestCase(OpportunityModel, TestCase):
+
def test_comment_add(self):
response = self.client.post(
'/opportunities/comment/add/', {'opportunityid': self.opportunity.id})
@@ -188,11 +209,21 @@ class CommentTestCase(OpportunityModel, TestCase):
'/opportunities/comment/remove/', {'comment_id': self.comment.id})
self.assertEqual(response.status_code, 200)
+ def test_comment_form_valid(self):
+ response = self.client.post(
+ '/opportunities/comment/add/', {'opportunityid': self.opportunity.id,
+ 'comment': 'hello'})
+ self.assertEqual(response.status_code, 200)
+
class AttachmentTestCase(OpportunityModel, TestCase):
+
def test_attachment_add(self):
+ upload_file = open('static/images/user.png', 'rb')
url = "/opportunities/attachment/add/"
- data = {'opportunityid': self.opportunity.id}
+ data = {'opportunityid': self.opportunity.id,
+ 'attachment': SimpleUploadedFile(
+ upload_file.name, upload_file.read())}
response = self.client.post(url, data)
self.assertEqual(response.status_code, 200)
@@ -204,9 +235,9 @@ class AttachmentTestCase(OpportunityModel, TestCase):
class TestGetOpportunitiesView(OpportunityModel, TestCase):
+
def test_get_page(self):
url = "/opportunities/get/list/"
resp = self.client.get(url)
self.assertEqual(resp.status_code, 200)
self.assertIsNotNone(resp.context['opportunities'])
-
diff --git a/static/images/company.png b/static/images/company.png
new file mode 100644
index 00000000..fb2d9349
Binary files /dev/null and b/static/images/company.png differ
diff --git a/templates/marketing/campaign/details.html b/templates/marketing/campaign/details.html
index bbc17464..44eaa309 100644
--- a/templates/marketing/campaign/details.html
+++ b/templates/marketing/campaign/details.html
@@ -2,561 +2,545 @@
{% load staticfiles %}
{% load paginate %}
{% block content %}
-{{ block.super }}
+{{ block.super }}
{% endblock %}
{% block js_block %}
-{% endblock js_block %}
\ No newline at end of file
+{% endblock js_block %}
diff --git a/templates/marketing/campaign/index.html b/templates/marketing/campaign/index.html
index e7f00630..b4ceb6b7 100644
--- a/templates/marketing/campaign/index.html
+++ b/templates/marketing/campaign/index.html
@@ -31,7 +31,7 @@
Primary {{ campaign.title }} |
5478 |
- {{ campaign.created_on }}
+ {{ campaign.sent_on_format }}
|
20.6% 125 Opened
@@ -40,7 +40,10 @@
15.5% 78 Clicked
|
-
+
+
|
|
@@ -49,116 +52,6 @@
No records found! |
{% endfor %}
-
@@ -168,4 +61,4 @@
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/templates/marketing/campaign/new.html b/templates/marketing/campaign/new.html
index b699aeb8..b4ceb6b7 100644
--- a/templates/marketing/campaign/new.html
+++ b/templates/marketing/campaign/new.html
@@ -6,280 +6,59 @@