marketing module and invoicing enhancements

This commit is contained in:
Ashwin 2019-07-11 20:07:12 +05:30
parent b41b0fe7a1
commit abcd47f600
33 changed files with 881 additions and 178 deletions

View file

@ -1,9 +1,14 @@
{% extends 'sales/base.html' %}
{% load staticfiles %}
{% load paginate %}
{% block extralinks %}
{% load thumbnail %}
{% block extralinks %}
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
<style>
.form-group label {
font-weight: 800;
}
</style>
{% endblock %}
{% block content %}
<!-- main_container starts here -->
@ -145,7 +150,8 @@
{% with tags=each_account.tags.all %}
{% if tags %}
{% for tag in tags %}
<span class="text-left color{{forloop.counter}}" id="list_tag">{{ tag.name }}</span>
<span class="text-left color{{forloop.counter}} tag_class_acc" id="list_tag"
data-link="{{tag.id}}" style="cursor: pointer;">{{ tag.name }}</span>
{% endfor %}
{% else %}
No Tags
@ -234,7 +240,8 @@
{% with tags=each_account.tags.all %}
{% if tags %}
{% for tag in tags %}
<span class="text-left color{{forloop.counter}}" id="list_tag">{{ tag.name }}</span>
<span class="text-left color{{forloop.counter}} tag_class_acc" data-link="{{tag.id}}"
style="cursor: pointer;" id="list_tag">{{ tag.name }}</span>
{% endfor %}
{% else %}
No Tags
@ -644,6 +651,12 @@
$("#close-tab").click(function (e) {
$("#tab_status").val('Closed');
})
$(".tag_class_acc").click(function () {
// $(".tag_class_acc").css('cursor', 'pointer')
url = "{% url 'accounts:list' %}"
url = url + "?tag=" + $(this).attr('data-link')
window.location.href = url;
});
// $(".account_modal").click(function (e) {
// console.log('clicked')

View file

@ -1,6 +1,13 @@
{% extends 'sales/base.html' %}
{% load staticfiles %}
{% load paginate %}
{% block extralinks %}
<style>
.form-group label{
font-weight: 800;
}
</style>
{% endblock %}
{% block content %}
<!-- main_container starts here -->
<div class="main_container">

View file

@ -1,3 +1,4 @@
import arrow
import binascii
import os
import time
@ -280,6 +281,10 @@ class Document(models.Model):
def __str__(self):
return self.title
@property
def created_on_arrow(self):
return arrow.get(self.created_on).humanize()
def generate_key():
return binascii.hexlify(os.urandom(8)).decode()

View file

@ -4,6 +4,11 @@
{% load thumbnail %}
{% block extralinks %}
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
<style>
.form-group label{
font-weight: 800;
}
</style>
{% endblock %}
{% block content %}
<!-- main_container starts here -->
@ -119,7 +124,7 @@
None
{% endif %}
</td>
<td>{{document.created_on}}</td>
<td title="{{document.created_on}}">{{document.created_on_arrow}}</td>
<td>{{document.status}}</td>
<td>
{% with document_users=document.shared_to.all %}

View file

@ -4,6 +4,11 @@
{% load thumbnail %}
{% block extralinks %}
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
<style>
.form-group label{
font-weight: 800;
}
</style>
{% endblock %}
{% block content %}
<!-- main_container starts here -->

View file

@ -1,3 +1,5 @@
import arrow
from django.db import models
from django.utils.translation import pgettext_lazy
from django.utils.translation import ugettext_lazy as _
@ -43,3 +45,7 @@ class Event(models.Model):
disabled = models.BooleanField(default=False)
date_of_meeting = models.DateField(blank=True, null=True)
# tags = models.ManyToManyField(Tag)
@property
def created_on_arrow(self):
return arrow.get(self.created_on).humanize()

View file

@ -4,6 +4,11 @@
{% load thumbnail %}
{% block extralinks %}
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
<style>
.form-group label{
font-weight: 800;
}
</style>
{% endblock %}
{% block content %}
<!-- main_container starts here -->
@ -179,7 +184,7 @@
<td>{{ event.start_date }} </td>
<td>{{ event.date_of_meeting }} </td>
<td>{{ event.end_date }} </td>
<td>{{ event.created_on|date:'d-m-Y' }}</td>
<td title="{{ event.created_on|date:'d-m-Y' }}">{{ event.created_on_arrow }}</td>
<td>
{% if event.created_by %}
{% if event.created_by.profile_pic %}

View file

@ -1,3 +1,4 @@
import arrow
from django.db import models
from django.utils.translation import ugettext_lazy as _
from common.models import Address, User
@ -93,3 +94,7 @@ class Invoice(models.Model):
return True
else:
return False
@property
def created_on_arrow(self):
return arrow.get(self.created_on).humanize()

View file

@ -6,6 +6,12 @@
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-tagsinput/1.3.6/jquery.tagsinput.min.css" rel="stylesheet">
<link rel="stylesheet" type="text/css"
href="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/themes/start/jquery-ui.css" />
<style>
.form-group label{
font-weight: 800;
color:black;
}
</style>
{% endblock %}
<nav aria-label="breadcrumb">
<ol class="breadcrumb">

View file

@ -8,6 +8,10 @@
.opacity_block {
opacity: 0.2;
}
.form-group label{
font-weight: 800;
color:black;
}
</style>
{% endblock extralinks %}
<!-- breadcrumb starts here -->

View file

@ -4,6 +4,11 @@
{% load thumbnail %}
{% block extralinks %}
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
<style>
.form-group label{
font-weight: 800;
}
</style>
{% endblock %}
{% block content %}
<!-- main_container starts here -->
@ -183,7 +188,7 @@
None
{% endif %}
</td>
<td>{{ invoice.created_on|date:'d-m-Y' }}</td>
<td title="{{ invoice.created_on|date:'d-m-Y' }}">{{ invoice.created_on_arrow }}</td>
<td class="actions">
<a href="{% url 'invoices:invoice_edit' invoice.id %}" class="btn btn-success edit"><i
class="fas fa-pencil-alt"></i></a>

View file

@ -4,6 +4,11 @@
{% load thumbnail %}
{% block extralinks %}
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
<style>
.form-group label{
font-weight: 800;
}
</style>
{% endblock %}
{% block content %}
<!-- main_container starts here -->
@ -196,7 +201,7 @@
{% with tags=lead.tags.all %}
{% if tags %}
{% for tag in tags %}
<span class="text-left color{{forloop.counter}}" id="list_tag">{{ tag.name }}</span>
<span class="text-left color{{forloop.counter}} tag_class_lead" data-link="{{tag.id}}" style="cursor: pointer;" id="list_tag">{{ tag.name }}</span>
{% endfor %}
{% else %}
No Tags
@ -291,7 +296,7 @@
{% with tags=lead.tags.all %}
{% if tags %}
{% for tag in tags %}
<span class="text-left color{{forloop.counter}}" id="list_tag">{{ tag.name }}</span>
<span class="text-left color{{forloop.counter}} tag_class_lead" data-link="{{tag.id}}" style="cursor: pointer;" id="list_tag">{{ tag.name }}</span>
{% endfor %}
{% else %}
No Tags
@ -668,6 +673,14 @@
});
});
$(".tag_class_lead").click(function () {
// $(".tag_class_opp").css('cursor', 'pointer')
url = "{% url 'leads:list' %}"
url = url + "?tag=" + $(this).attr('data-link')
window.location.href = url;
});
search = "{{search}}"
if (search == 'True') {

View file

@ -43,6 +43,9 @@ class LeadListView(SalesAccessRequiredMixin, LoginRequiredMixin, TemplateView):
Q(assigned_to__in=[self.request.user]) |
Q(created_by=self.request.user))
if self.request.GET.get('tag', None):
queryset = queryset.filter(tags__in = self.request.GET.getlist('tag'))
request_post = self.request.POST
if request_post:
if request_post.get('name'):

View file

@ -17,6 +17,8 @@ email_regex = '^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)
def csv_doc_validate(document):
temp_row = []
invalid_row = []
# this stores all the failed csv contacts
failed_contacts_csv = []
reader = csv.reader((document.read().decode("utf-8")).splitlines())
# csv_headers = ["first name", "last name", "email"]
csv_headers = ["first name", "email"]
@ -56,9 +58,11 @@ def csv_doc_validate(document):
each[csv_headers[x_index]] = cell_value
if invalid_each:
invalid_row.append(each)
failed_contacts_csv.append(list(each.values()))
else:
temp_row.append(each)
return {"error": False, "validated_rows": temp_row, "invalid_rows": invalid_row}
return {"error": False, "validated_rows": temp_row, "invalid_rows": invalid_row, "headers":csv_headers,
"failed_contacts_csv": failed_contacts_csv}
def get_validated_rows(wb, sheet_name, validated_rows, invalid_rows):
@ -141,14 +145,21 @@ class ContactListForm(forms.ModelForm):
self.fields['contacts_file'].widget.attrs.update({
"accept": ".csv,.xls,.xlsx,.xlsm,.xlsb,.xml",
})
self.fields['contacts_file'].required = True
# if self.instance is None:
# self.fields['contacts_file'].required = True
if self.instance.id is None:
self.fields['contacts_file'].required = True
else:
self.fields['contacts_file'].required = False
if self.data.get('contacts_file'):
self.fields['contacts_file'].widget.attrs.update({
"accept": ".csv,.xls,.xlsx,.xlsm,.xlsb,.xml",
})
def clean_name(self):
name = self.cleaned_data.get('name')
if ContactList.objects.filter(name__iexact=name).exclude(id=self.instance.id).exists():
raise forms.ValidationError('Contact List with this Name already exists.')
return name
def clean_contacts_file(self):
document = self.cleaned_data.get("contacts_file")
if document:
@ -158,8 +169,16 @@ class ContactListForm(forms.ModelForm):
else:
self.validated_rows = data.get("validated_rows", [])
self.invalid_rows = data.get("invalid_rows", [])
if self.invalid_rows:
raise forms.ValidationError('Uploaded file is not valid')
if len(self.validated_rows) == 0:
raise forms.ValidationError("All the contacts in the file are invalid.")
# self.headers = data.get("headers", [])
# self.failed_contacts_csv = data.get("failed_contacts_csv", [])
# failed_csv_data = []
# failed_csv_data = (self.failed_contacts_csv)
# failed_csv_data.insert(0, self.headers)
# if self.invalid_rows:
# self.add_error(None, json.dumps(failed_csv_data))
# raise forms.ValidationError('Uploaded file is not valid.')
return document
def clean_visible_to(self):
@ -193,11 +212,11 @@ class ContactForm(forms.ModelForm):
field.widget.attrs = {"class": "form-control"}
self.fields['name'].required = True
self.fields['last_name'].required = True
self.fields['city'].required = True
self.fields['state'].required = True
self.fields['email'].required = True
self.fields['company_name'].required = True
self.fields['last_name'].required = False
self.fields['city'].required = False
self.fields['state'].required = False
self.fields['company_name'].required = False
self.fields['contact_list'].required = False
class Meta:

View file

@ -1,3 +1,4 @@
import arrow
import os
from datetime import datetime, timedelta
from django.db import models
@ -42,6 +43,10 @@ class EmailTemplate(models.Model):
def created_by_user(self):
return self.created_by if self.created_by else None
@property
def created_on_arrow(self):
return arrow.get(self.created_on).humanize()
class ContactList(models.Model):
created_by = models.ForeignKey(
@ -104,6 +109,14 @@ class ContactList(models.Model):
'no_of_clicks'))['no_of_clicks__sum']
return clicks
@property
def created_on_arrow(self):
return arrow.get(self.created_on).humanize()
@property
def updated_on_arrow(self):
return arrow.get(self.updated_on).humanize()
class Contact(models.Model):
phone_regex = RegexValidator(
@ -132,6 +145,10 @@ class Contact(models.Model):
def __str__(self):
return self.email
@property
def created_on_arrow(self):
return arrow.get(self.created_on).humanize()
class Meta:
ordering = ['id', ]
@ -273,6 +290,18 @@ class Campaign(models.Model):
return contact_ids.count()
@property
def sent_on_arrow(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')
return arrow.get(c_schedule_date_time).humanize()
else:
c_created_on = convert_to_custom_timezone(
self.created_on, self.timezone)
# return c_created_on.strftime('%b %d, %Y %I:%M %p')
return arrow.get(self.created_on).humanize()
@receiver(models.signals.pre_delete, sender=Campaign)
def comment_attachments_delete(sender, instance, **kwargs):

View file

View file

@ -0,0 +1,87 @@
from django import template
register = template.Library()
LEADING_PAGE_RANGE_DISPLAYED = TRAILING_PAGE_RANGE_DISPLAYED = 0
LEADING_PAGE_RANGE = TRAILING_PAGE_RANGE = 0
NUM_PAGES_OUTSIDE_RANGE = 0
ADJACENT_PAGES = 2
def digg_paginator(context):
'''
To be used in conjunction with the object_list generic view.
Adds pagination context variables for use in displaying leading, adjacent and
trailing page links in addition to those created by the object_list generic
view.
'''
paginator = context['paginator']
page_obj = context['page_obj']
pages = paginator.num_pages
page = page_obj.number
in_leading_range = in_trailing_range = False
pages_outside_leading_range = pages_outside_trailing_range = range(0)
if pages <= LEADING_PAGE_RANGE_DISPLAYED + NUM_PAGES_OUTSIDE_RANGE + 1:
in_leading_range = in_trailing_range = True
page_range = [n for n in range(1, pages + 1)]
elif page <= LEADING_PAGE_RANGE:
in_leading_range = True
page_range = [n for n in range(1, LEADING_PAGE_RANGE_DISPLAYED + 1)]
pages_outside_leading_range = [
n + pages for n in range(0, -NUM_PAGES_OUTSIDE_RANGE, -1)]
elif page > pages - TRAILING_PAGE_RANGE:
in_trailing_range = True
page_range = [n for n in range(
pages - TRAILING_PAGE_RANGE_DISPLAYED + 1, pages + 1) if n > 0 and n <= pages]
pages_outside_trailing_range = [
n + 1 for n in range(0, NUM_PAGES_OUTSIDE_RANGE)]
else:
page_range = [n for n in range(
page - ADJACENT_PAGES, page + ADJACENT_PAGES + 1) if n > 0 and n <= pages]
pages_outside_leading_range = [
n + pages for n in range(0, -NUM_PAGES_OUTSIDE_RANGE, -1)]
pages_outside_trailing_range = [
n + 1 for n in range(0, NUM_PAGES_OUTSIDE_RANGE)]
# Now try to retain GET params, except for 'page'
# Add 'django.core.context_processors.request' to settings.TEMPLATE_CONTEXT_PROCESSORS beforehand
request = context['request']
params = request.GET.copy()
# if 'page' in params:
# del(params['page'])
# get_params = params.urlencode()
if 'bounced_contacts_page' in params:
del(params['bounced_contacts_page'])
get_params = params.urlencode()
if page_obj.has_previous():
previous_page = page_obj.previous_page_number()
else:
previous_page = 1
if page_obj.has_next():
next_page = page_obj.next_page_number()
else:
next_page = pages
return {
'pages': pages,
'bounced_contacts_page': page,
'previous': previous_page,
'next': next_page,
'has_previous': page_obj.has_previous(),
'has_next': page_obj.has_next(),
'page_range': page_range,
'in_leading_range': in_leading_range,
'in_trailing_range': in_trailing_range,
'pages_outside_leading_range': pages_outside_leading_range,
'pages_outside_trailing_range': pages_outside_trailing_range,
'get_params': get_params,
}
register.inclusion_tag("contact_list_digg_paginator.html",
takes_context=True)(digg_paginator)

View file

@ -6,7 +6,7 @@ from .views import (
edit_contact_list, delete_contact_list, failed_contact_list_detail, failed_contact_list_download_delete,
campaign_link_click, campaign_open, demo_file_download, delete_contact, unsubscribe_from_campaign, contact_detail,
edit_failed_contact, delete_failed_contact, download_contacts_for_campaign, create_campaign_from_template,
download_links_clicked
download_links_clicked, delete_multiple_contacts, download_failed_contacts
)
app_name = 'marketing'
@ -48,4 +48,6 @@ urlpatterns = [
path('download-contacts-for-campaign/<int:compaign_id>/', download_contacts_for_campaign, name="download_contacts_for_campaign"),
path('create-campaign-from-template/<int:template_id>/', create_campaign_from_template, name="create_campaign_from_template"),
path('download-links-clicked/<int:campaign_id>/', download_links_clicked, name="download_links_clicked"),
path('delete_multiple_contacts/', delete_multiple_contacts, name="delete_multiple_contacts"),
path('download-failed-contacts/<int:contact_list_id>/', download_failed_contacts, name="download_failed_contacts"),
]

View file

@ -330,12 +330,20 @@ def edit_contact(request, pk):
@marketing_access_required
def delete_contact(request, pk):
contact_obj = get_object_or_404(Contact, pk=pk)
if not (request.user.role == 'ADMIN' or request.user.is_superuser or contact_obj.created_by == request.user or
(contact_obj.id in request.user.marketing_contactlist.all().values_list('contacts', flat=True))):
raise PermissionDenied
contact_obj.delete()
if request.GET.get('from_contact'):
return redirect(reverse('marketing:contact_list_detail', args=(request.GET.get('from_contact'),)))
if contact_obj.contact_list.count() == 1:
contact_obj.delete()
return redirect(reverse('marketing:contact_list_detail', args=(request.GET.get('from_contact'),)))
else:
contact_list_obj = get_object_or_404(ContactList, pk=request.GET.get('from_contact'))
contact_obj.contact_list.remove(contact_list_obj)
return redirect(reverse('marketing:contact_list_detail', args=(request.GET.get('from_contact'),)))
else:
contact_obj.delete()
return redirect('marketing:contacts_list')
@ -345,7 +353,9 @@ def contact_list_detail(request, pk):
contact_list = get_object_or_404(ContactList, pk=pk)
if not (request.user.role == 'ADMIN' or request.user.is_superuser or contact_list.created_by == request.user):
raise PermissionDenied
contacts_list = contact_list.contacts.all()
contacts_list = contact_list.contacts.filter(is_bounced=False)
bounced_contacts_list = contact_list.contacts.filter(is_bounced=True)
bounced_contacts_list_count = contact_list.contacts.filter(is_bounced=True).count()
if request.POST:
if request.POST.get('name'):
contacts_list = contacts_list.filter(
@ -356,7 +366,29 @@ def contact_list_detail(request, pk):
if request.POST.get('company_name'):
contacts_list = contacts_list.filter(
company_name=request.POST.get('company_name'))
data = {'contact_list': contact_list, "contacts_list": contacts_list}
if request.POST.get('name'):
bounced_contacts_list = bounced_contacts_list.filter(
name__icontains=request.POST.get('name'))
if request.POST.get('email'):
bounced_contacts_list = bounced_contacts_list.filter(
email__icontains=request.POST.get('email'))
if request.POST.get('company_name'):
bounced_contacts_list = bounced_contacts_list.filter(
company_name=request.POST.get('company_name'))
page = request.GET.get('bounced_contacts_page', 1)
paginator = Paginator(bounced_contacts_list, 10)
try:
bounced_contacts_list = paginator.page(page)
except:
bounced_contacts_list = paginator.page(paginator.num_pages)
data = {'contact_list': contact_list, "contacts_list": contacts_list,
"bounced_contacts_list":bounced_contacts_list,
'bounced_contacts_list_count': bounced_contacts_list_count,
# these two are added for digg pagintor
'paginator':paginator,'page_obj': bounced_contacts_list,}
return render(request, 'marketing/lists/detail.html', data)
@ -941,3 +973,55 @@ def download_links_clicked(request, campaign_id):
response = HttpResponse(data, content_type='text/plain')
response['Content-Disposition'] = 'attachment; filename={}'.format('data_downloads.csv')
return response
@login_required(login_url='/login')
@marketing_access_required
def delete_multiple_contacts(request):
contacts_list = Contact.objects.filter(id__in=request.POST.getlist('selected_list[]'))
shared_contact_lists = request.user.marketing_contactlist.all().values_list('contacts', flat=True)
cannot_be_deleted = []
error = False
for contact_obj in contacts_list:
if not (request.user.role == 'ADMIN' or request.user.is_superuser or contact_obj.created_by == request.user or (contact_obj.id in shared_contact_lists)):
cannot_be_deleted.append(contact_obj.email)
error = True
if len(cannot_be_deleted) == 0:
error = False
for contact_obj in contacts_list:
if request.POST.get('from_contact'):
if contact_obj.contact_list.count() == 1:
contact_obj.delete()
else:
contact_list_obj = get_object_or_404(ContactList, pk=request.POST.get('from_contact'))
contact_obj.contact_list.remove(contact_list_obj)
return JsonResponse({'error':False, 'refresh': True})
else:
message = "You don't have permission to delete {}".format(', '.join(cannot_be_deleted))
return JsonResponse({'error': True, 'message' : message })
@login_required
@marketing_access_required
def download_failed_contacts(request, contact_list_id):
contact_list_obj = get_object_or_404(ContactList, pk=contact_list_id)
if not (request.user.role == 'ADMIN' or request.user.is_superuser or contact_list_obj.created_by == request.user):
raise PermissionDenied
failed_contacts = contact_list_obj.failed_contacts.values('company_name', 'email', 'name', 'last_name', 'city', 'state')
if failed_contacts:
data = [
'company name,email,first name,last name,city,state\n',
]
for contact in failed_contacts:
data.append((', '.join(contact.values()) + '\n'))
response = HttpResponse(
data, content_type='text/plain')
response['Content-Disposition'] = 'attachment; filename={}'.format(
'failed_contacts.csv')
return response
else:
return HttpResponse('No Data')

View file

@ -4,6 +4,11 @@
{% load thumbnail %}
{% block extralinks %}
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
<style>
.form-group label {
font-weight: 800;
}
</style>
{% endblock %}
{% block content %}
<!-- main_container starts here -->
@ -135,9 +140,8 @@
{% for opportunity in opportunity_list %}
<tr class="text-center">
<td scope="row">{{ forloop.counter }}</td>
<td><a href="#"
data-toggle="modal"
data-target="#exampleModalCenter_opportunity{{opportunity.id}}">{{ opportunity.name }}</a></td>
<td><a href="#" data-toggle="modal"
data-target="#exampleModalCenter_opportunity{{opportunity.id}}">{{ opportunity.name }}</a></td>
<td>
{% with opportunity_users=opportunity.assigned_to.all %}
{% for user in opportunity_users %}
@ -161,7 +165,8 @@
{% with tags=opportunity.tags.all %}
{% if tags %}
{% for tag in tags %}
<span class="text-left color{{forloop.counter}}" id="list_tag">{{ tag.name }}</span>
<span class="text-left color{{forloop.counter}} tag_class_opp" data-link="{{tag.id}}"
style="cursor: pointer;" id="list_tag">{{ tag.name }}</span>
{% endfor %}
{% else %}
No Tags
@ -190,7 +195,8 @@
<td>{% if opportunity.lead_source %}{{ opportunity.lead_source }}{% else %}Not Specified{% endif %}
</td>
<td class="actions">
<a href="{% url 'opportunities:opp_view' opportunity.id %}" class="btn btn-info view"><i class="fas fa-eye"></i></a>
<a href="{% url 'opportunities:opp_view' opportunity.id %}" class="btn btn-info view"><i
class="fas fa-eye"></i></a>
<a href="{% url 'opportunities:opp_edit' opportunity.id %}" class="btn btn-success edit"><i
class="fas fa-pencil-alt"></i></a>
{% if request.user == opportunity.created_by or request.user.role == "ADMIN" or request.user.is_superuser %}
@ -393,6 +399,13 @@
$('#id_tag').select2();
});
$(".tag_class_opp").click(function () {
// $(".tag_class_opp").css('cursor', 'pointer')
url = "{% url 'opportunity:list' %}"
url = url + "?tag=" + $(this).attr('data-link')
window.location.href = url;
});
search = "{{search}}"
if (search == 'True') {

View file

@ -459,7 +459,7 @@ $color_2: #000;
.form-group{
margin-bottom: 10px;
label{
color: $text_color;
color: black;
font-size: 0.85rem;
font-weight: 600;
text-transform: none;

View file

@ -8,6 +8,9 @@
.table_container_row .card .card-body table tbody .due-date td {
color: red;
}
.form-group label{
font-weight: 800;
}
</style>
{% endblock %}
{% block content %}

View file

@ -1,3 +1,5 @@
import arrow
from django.db import models
from common.models import User
from django.utils.translation import ugettext_lazy as _
@ -16,3 +18,7 @@ class Teams(models.Model):
class Meta:
ordering = ('id',)
@property
def created_on_arrow(self):
return arrow.get(self.created_on).humanize()

View file

@ -4,6 +4,11 @@
{% load thumbnail %}
{% block extralinks %}
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
<style>
.form-group label{
font-weight: 800;
}
</style>
{% endblock %}
{% block content %}
<!-- main_container starts here -->
@ -158,7 +163,7 @@
None
{% endif %}
</td>
<td>{{ team.created_on|date:'d-m-Y' }}</td>
<td title="{{ team.created_on|date:'d-m-Y' }}">{{ team.created_on_arrow }}</td>
<td class="actions">
{% if request.user == team.created_by or request.user.role == 'ADMIN' or reques.user.is_superuser %}
<a href="{% url 'teams:team_detail' team.id %}" class="btn btn-info edit"><i

View file

@ -0,0 +1,46 @@
{% spaceless %}
{% ifnotequal pages 1 %}
<!-- single page -->
<!-- "bounced_contacts_page", instead of "page" is the query param, since there are two objects with pagination in the same page
and to differentiate between "page" for contacts_list and "bounced_contacts_page" for bounced_contacts_list -->
{% ifnotequal bounced_contacts_page 1 %}
<li><a href="{% if get_params %}?{{ get_params }}&{% else %}?{% endif %}bounced_contacts_page=1"
rel="page">{{"<<"|safe}}</a></li>
{% endifnotequal %}
{% if has_previous %}
<li><a href="{% if get_params %}?{{ get_params }}&{% else %}?{% endif %}bounced_contacts_page={{ previous }}"
rel="page">{{"<"|safe}}</a></li>
{% endif %}
{% if not in_leading_range %}
{% for p in pages_outside_trailing_range %}
<li><a href="{% if get_params %}?{{ get_params }}&{% else %}?{% endif %}bounced_contacts_page={{ p }}"
rel="page">{{ p }}</a></li>
{% endfor %}
<!-- <li><span class="ellipsis">...</span></li> -->
{% endif %}
{% for p in page_range %}
{% if p == bounced_contacts_page %}
<li><span class="active">{{ p }}</span></li>
{% else %}
<li><a href="{% if get_params %}?{{ get_params }}&{% else %}?{% endif %}bounced_contacts_page={{ p }}"
rel="page">{{ p }}</a></li>
{% endif %}
{% endfor %}
{% if not in_trailing_range %}
<!-- <li><span class="ellipsis">...</span></li> -->
{% for p in pages_outside_leading_range reversed %}
<li><a href="{% if get_params %}?{{ get_params }}&{% else %}?{% endif %}bounced_contacts_page={{ p }}"
rel="page">{{ p }}</a></li>
{% endfor %}
{% endif %}
{% if has_next %}
<li><a href="{% if get_params %}?{{ get_params }}&{% else %}?{% endif %}bounced_contacts_page={{ next }}"
rel="page">{{">"|safe}}</a></li>
{% endif %}
{% ifnotequal bounced_contacts_page pages %}
<li><a href="{% if get_params %}?{{ get_params }}&{% else %}?{% endif %}bounced_contacts_page={{ pages }}"
rel="page">{{">>"|safe}}</a></li>
{% endifnotequal %}
{% endifnotequal %}
{% endspaceless %}

View file

@ -94,8 +94,8 @@
<!-- <span class="badge badge-primary">Primary</span> -->
<a href="{% url 'marketing:campaign_details' campaign.id %}">{{ campaign.title }} </a></td>
<td class="text-center">{{campaign.get_all_emails_count}}</td>
<td>
{{ campaign.sent_on_format }}
<td title="{{ campaign.sent_on_format }}">
{{ campaign.sent_on_arrow }}
</td>
<td>
{{ campaign.created_by }}

View file

@ -144,7 +144,7 @@
<tr>
<th width="30%">Title</th>
<th width="30%">Tags</th>
<th width="50%">Contact Lists</th>
<th width="50%">Contact List</th>
</tr>
</thead>
<tbody>

View file

@ -89,7 +89,7 @@
href="{% url 'marketing:email_template_detail' email_template.id %}">{{ email_template.title }}</a>
</td>
<td scope="row">{{ email_template.created_by }}</td>
<td scope="row">{{ email_template.created_on }}</td>
<td scope="row" title="{{ email_template.created_on }}">{{ email_template.created_on_arrow }}</td>
<td class="text-center"><a
href="{% url 'marketing:create_campaign_from_template' email_template.id %}" class="a_color"
data-toggle="tooltip" data-placement="bottom"

View file

@ -102,7 +102,7 @@
<td class="text-center">{{ contact.email }}</td>
<td class="text-center">{{ contact.company_name }}</td>
<td>{{ contact.created_by }}</td>
<td>{{ contact.created_on }}</td>
<td title="{{contact.created_on}}">{{ contact.created_on_arrow }}</td>
<td>
{% for contact_list in contact.contact_list.all %}
<span> <a
@ -159,7 +159,7 @@
url = $(this).attr('href')
var contact_lists = parseInt($(this).attr('data-other-contacts-lists'));
if (contact_lists > 1) {
if (!confirm('This contact exists in other contact lists too. Are you sure you want to delete this contact?'))
if (!confirm('This contact exists in other Contact List too. Are you sure you want to delete this contact?'))
return;
window.location = $(this).attr('href');
} else {

View file

@ -1,131 +1,278 @@
{% extends 'marketing/base.html' %}
{% load staticfiles %}
{% load paginate %}
{% load digg_paginator %}
{% block content %}
{{ block.super }}
<nav aria-label="breadcrumb">
<ol class="breadcrumb mb-5">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'marketing:contact_lists' %}">Contact List</a></li>
<li class="breadcrumb-item active">{{contact_list.name}}</li>
</ol>
</nav>
<div class="main_container ml-5 mr-5">
<!-- main_container starts here -->
<div class="main_container">
<!-- heading_create starts here -->
<div class="row marl">
<div class="filter_row list_filter_row row marl col-md-12 mb-2">
<div class="">
<div class="card">
<div class="card-body">
<form id="leads_filter" action="" method="POST">
<div class="card-body ">
<div class="card-title">Filters</div>
<div class="row marl">
<div class="filter_col col-md-3">
<div class="form-group">
<label for="exampleInputEmail1">Name</label>
<input type="text" class="form-control" placeholder="Name" name="name"
value="{{request.POST.name}}">
</div>
<div class="col-lg-12 text-right">
<span class="d-inline">
<a href="{% url 'marketing:contact_list_new' %}" class="primary_btn">Add New Contact List</a>
</span>
</div>
</div>
<div class="filter_row list_filter_row row marl">
<div class="col-md-12">
<div class="card">
<div class="card-body">
<form id="leads_filter" action="" method="POST">
<div class="card-body ">
<div class="card-title">Filters</div>
<div class="row marl">
<div class="filter_col col-md-3">
<div class="form-group">
<label for="exampleInputEmail1">Name</label>
<input type="text" class="form-control" placeholder="Name" name="name"
value="{{request.POST.name}}">
</div>
<div class="filter_col col-md-3">
<div class="form-group">
<label for="exampleInputEmail1">Email</label>
<input type="text" class="form-control" placeholder="Email" name="email"
value="{{request.POST.email}}">
</div>
</div>
<div class="filter_col col-md-3">
<div class="form-group">
<label for="exampleInputEmail1">Email</label>
<input type="text" class="form-control" placeholder="Email" name="email"
value="{{request.POST.email}}">
</div>
<div class="filter_col col-md-3">
<div class="form-group">
<label for="exampleInputEmail1">Company Name</label>
<input type="text" class="form-control" placeholder="Company Name" name="company_name"
value="{{request.POST.company_name}}">
</div>
</div>
<div class="filter_col col-md-3">
<div class="form-group">
<label for="exampleInputEmail1">Company Name</label>
<input type="text" class="form-control" placeholder="Company Name" name="company_name"
value="{{request.POST.company_name}}">
</div>
<input type="hidden" name="tab_status" id="tab_status">
<div class="filter_col col-2">
<div class="form-group buttons_row">
<button class="btn btn-primary save" type="submit">Search</button>
<a href="" class="btn btn-default clear" onclick="window.location.reload">Clear</a>
</div>
</div>
<input type="hidden" name="tab_status" id="tab_status">
<div class="filter_col col-2">
<div class="form-group buttons_row">
<button class="btn btn-primary save" type="submit">Search</button>
<a href="" class="btn btn-default clear" onclick="window.location.reload">Clear</a>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="col-md-12">
<div class="table_container_row no_mar_top">
<div class="card">
<div class="card-body">
<div class="card-title text-right">
<span class="float-left">{{ contact_list.name }} - {{ contacts_list|length }}</span>
{% if contact_list.failed_contacts.all|length > 0 %}
<a href="{% url 'marketing:failed_contact_list_detail' contact_list.id %}" class="primary_btn">Failed
Contacts</a>
{% endif %}
<span class="filter_toggle">
<a href="#" class="primary_btn"><i class="fas fa-filter"></i></a>
</span>
<a href="{% url 'marketing:contact_list_new' %}" class="primary_btn">Add New Contact List</a>
</div>
<div class="table-responsive table-bordered ">
<table class="table">
<thead>
<tr>
<th width="5%">ID</th>
<th width="20%">Name</th>
<th width="20%">Email</th>
<th width="10%">Actions</th>
</tr>
</thead>
<tbody>
<tr>
<span><b>Tags : </b></span>
{% for tag in contact_list.tags.all %}
<span class="text-left color{{forloop.counter}} tag_class_cl" id="list_tag" data-link="{{tag.id}}"
style="cursor: pointer;">{{tag.name}}</span>
{% empty %}
<span class="text-left">No Tags</span>
{% endfor %}
</tr>
{% if per_page %}
{% paginate per_page contacts_list %}
{% else%}
{% paginate 10 contacts_list %}
{% endif %}
{% for contact in contacts_list %}
<tr style="text-align:center;">
<td scope="row">{{ forloop.counter }}</td>
<td>{{ contact.name }}</td>
<td> <a href="{% url 'marketing:contact_detail' contact.id %}">{{ contact.email }}</a> </td>
<td class="actions">
<a href="{% url 'marketing:edit_contact' contact.id %}?from_contact={{contact_list.id}}"
class="btn btn-success edit edit_contact"
data-other-contacts-lists='{{contact.contact_list.all|length}}'><i class="fas fa-edit"></i></a>
<!-- <a href="/contacts/1/edit/" class="btn btn-info duplicate"><i class="fas fa-copy"></i></a> -->
<a href="{% url 'marketing:delete_contact' contact.id %}?from_contact={{contact_list.id}}"
class="btn btn-danger delete remove_account"
data-other-contacts-lists='{{contact.contact_list.all|length}}'><i class="fas fa-trash"></i></a>
</td>
</tr>
{% empty %}
<tr style="text-align:center;">
<td colspan="6">No records found!</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="marl row text-center mt-5">
{% show_pages %}
<!-- heading_create ends here -->
<!-- filter_row starts here -->
<div class="filter_row row marl">
<div class="col-md-12 col-lg-12 col-xl-12">
<div class="table_container_row row marl no-gutters">
<div class="col-md-12">
<ul class="nav nav-tabs" id="myTab" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="open-tab" data-toggle="tab" href="#open" role="tab" aria-controls="open"
aria-selected="true">Contacts ({{contacts_list|length}})</a>
</li>
<li class="nav-item">
<a class="nav-link" id="close-tab" data-toggle="tab" href="#close" role="tab" aria-controls="close"
aria-selected="false">Bounced ({{bounced_contacts_list_count}})</a>
</li>
{% if contact_list.failed_contacts.all %}
<li class="nav-item">
<a class="nav-link" id="close-tab" data-toggle="tab" href="#failed_contacts" role="tab"
aria-controls="close" aria-selected="false">Failed Contacts</a>
</li>
{% endif %}
</ul>
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="open" role="tabpanel" aria-labelledby="open">
<div class="card">
<div class="card-body">
<div class="panel-heading-list card-title text-right">
<span class="total_count float-left">Contacts - {% if show_pageitems %}
{% show_pageitems %}{% else %}{{contacts_list|length}}{% endif %}</span>
<span class="filter_toggle ">
<a href="#" class="primary_btn"><i class="fas fa-filter"></i></a>
</span>
<button href="#" class="primary_btn" id="delete_all"
style="background:black; color: white;">Delete</button>
</div>
<div class="table-responsive table-bordered ">
<table class="table">
<thead>
<tr>
<th width="1%">
<input type="checkbox" name="check_all" id="check_all">
</th>
<th width="5%">ID</th>
<th width="20%">Name</th>
<th width="20%">Email</th>
<th width="10%">Actions</th>
</tr>
</thead>
<tbody>
<tr>
<span><b>Tags : </b></span>
{% for tag in contact_list.tags.all %}
<span class="text-left color{{forloop.counter}} tag_class_cl" id="list_tag"
data-link="{{tag.id}}" style="cursor: pointer;">{{tag.name}}</span>
{% empty %}
<span class="text-left">No Tags</span>
{% endfor %}
</tr>
{% if per_page %}
{% paginate per_page contacts_list %}
{% else%}
{% paginate 10 contacts_list %}
{% endif %}
{% for contact in contacts_list %}
<tr style="text-align:center;">
<td>
<input type="checkbox" class="check_delete" name="{{contact.name}}" id="{{contact.id}}"
value="{{contact.id}}">
</td>
<td scope="row">{{ forloop.counter }}</td>
<td>{{ contact.name }}</td>
<td> <a href="{% url 'marketing:contact_detail' contact.id %}">{{ contact.email }}</a> </td>
<td class="actions">
<a href="{% url 'marketing:edit_contact' contact.id %}?from_contact={{contact_list.id}}"
class="btn btn-success edit edit_contact"
data-other-contacts-lists='{{contact.contact_list.all|length}}'><i
class="fas fa-edit"></i></a>
<!-- <a href="/contacts/1/edit/" class="btn btn-info duplicate"><i class="fas fa-copy"></i></a> -->
<a href="{% url 'marketing:delete_contact' contact.id %}?from_contact={{contact_list.id}}"
class="btn btn-danger delete remove_account"
data-other-contacts-lists='{{contact.contact_list.all|length}}'><i
class="fas fa-trash"></i></a>
</td>
</tr>
{% empty %}
<tr style="text-align:center;">
<td colspan="6">There are no records</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="text-center row marl mt-3">
{% show_pages %}
</div>
</div>
</div>
<div class="tab-pane fade" id="close" role="tabpanel" aria-labelledby="close">
<div class="card">
<div class="card-body">
<div class="panel-heading-list card-title text-right">
<span class="total_count float-left">Bounced Contacts - {{bounced_contacts_list_count}}</span>
<span class="filter_toggle ">
<a href="#" class="primary_btn"><i class="fas fa-filter"></i></a>
</span>
<button href="#" class="primary_btn" id="delete_all_bounced"
style="background:black; color: white;">Delete</button>
</div>
<div class="table-responsive table-bordered ">
<table class="table">
<thead>
<tr>
<th width="1%">
<input type="checkbox" name="check_all" id="check_all_bounced">
</th>
<th width="5%">ID</th>
<th width="20%">Name</th>
<th width="20%">Email</th>
<th width="10%">Actions</th>
</tr>
</thead>
<tbody>
<tr>
<span><b>Tags : </b></span>
{% for tag in contact_list.tags.all %}
<span class="text-left color{{forloop.counter}} tag_class_cl" id="list_tag"
data-link="{{tag.id}}" style="cursor: pointer;">{{tag.name}}</span>
{% empty %}
<span class="text-left">No Tags</span>
{% endfor %}
</tr>
{% if per_page %}
{% paginate per_page bounced_contacts_list %}
{% else%}
{% paginate 10 bounced_contacts_list %}
{% endif %}
{% for contact in bounced_contacts_list %}
<tr style="text-align:center;">
<td>
<input type="checkbox" class="check_delete_bounced" name="{{contact.name}}"
id="{{contact.id}}" value="{{contact.id}}">
</td>
<td scope="row">{{ forloop.counter }}</td>
<td>{{ contact.name }}</td>
<td> <a href="{% url 'marketing:contact_detail' contact.id %}">{{ contact.email }}</a> </td>
<td class="actions">
<a href="{% url 'marketing:edit_contact' contact.id %}?from_contact={{contact_list.id}}"
class="btn btn-success edit edit_contact"
data-other-contacts-lists='{{contact.contact_list.all|length}}'><i
class="fas fa-edit"></i></a>
<!-- <a href="/contacts/1/edit/" class="btn btn-info duplicate"><i class="fas fa-copy"></i></a> -->
<a href="{% url 'marketing:delete_contact' contact.id %}?from_contact={{contact_list.id}}"
class="btn btn-danger delete remove_account"
data-other-contacts-lists='{{contact.contact_list.all|length}}'><i
class="fas fa-trash"></i></a>
</td>
</tr>
{% empty %}
<tr style="text-align:center;">
<td colspan="6">There are no records</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="text-center row marl mt-3">
<ul class="pagination">
{% digg_paginator %}
</ul>
{% comment %}
{% show_pages %}
{% endcomment %}
</div>
</div>
</div>
<div class="tab-pane fade" id="failed_contacts" role="tabpanel" aria-labelledby="failed_contacts">
<div class="card">
<div class="card-body">
<div class="panel-heading-list card-title text-right">
<span class="total_count float-left">Failed Contact List</span>
<span class="filter_toggle ">
<a href="#" class="primary_btn"><i class="fas fa-filter"></i></a>
</span>
</div>
<div class="table-responsive table-bordered ">
<span>
<h5 class="mt-3 text-center">
<a href="{% url 'marketing:download_failed_contacts' contact_list.id %}"
class="">Download Invalid Contacts</a></span></h5>
</div>
</div>
</div>
</div>
</div>
<br clear="all">
</div>
</div>
</div>
</div>
<!-- filter_row ends here -->
<!-- accounts list start -->
<!-- accounts list end -->
</div>
<!-- main_container ends here -->
{% endblock %}
{% block js_block %}
@ -135,6 +282,131 @@
$(".list_filter_row").toggle();
});
$('#id_tag').select2();
$('#delete_all').hide()
$('#delete_all_bounced').hide()
$(".tag_class_cl").click(function () {
// $(".tag_class_opp").css('cursor', 'pointer')
url = "{% url 'marketing:contact_lists' %}"
url = url + "?tag=" + $(this).attr('data-link')
window.location.href = url;
})
$("#check_all").click(function () {
$(".check_delete").prop('checked', $(this).prop('checked'))
if ($('#check_all').prop('checked')) {
$('#delete_all').show()
}
else {
$('#delete_all').hide()
}
});
$('.check_delete').on('change', function () {
// console.log('changed')
if ($('.check_delete:checked').length > 1) {
$('#delete_all').show()
}
else {
$('#delete_all').hide()
}
})
$('#delete_all').click(function (e) {
e.preventDefault()
if (!confirm('Are you sure you want to delete the selected contacts ?')) {
$('#check_all').prop('checked', false)
$('.check_delete').prop('checked', false)
$('#delete_all').hide()
return;
}
$('#delete_all').attr('disabled', 'disabled')
var selected = [];
$('.check_delete:checked').each(function () {
selected.push($(this).attr('value'));
// console.log(selected)
});
console.log(selected)
$.ajax({
url: "{% url 'marketing:delete_multiple_contacts' %}",
type: 'POST',
data: {
'selected_list': selected,
'from_contact': "{{contact_list.id}}",
},
success: function (data) {
console.log(data)
if (data['error'] === false) {
window.location.reload()
}
else {
$('#delete_all').removeAttr('disabled', 'disabled')
alert(data['message'])
}
},
});
})
// for bounced
$("#check_all_bounced").click(function () {
$(".check_delete_bounced").prop('checked', $(this).prop('checked'))
if ($('#check_all_bounced').prop('checked')) {
$('#delete_all_bounced').show()
}
else {
$('#delete_all_bounced').hide()
}
});
$('.check_delete_bounced').on('change', function () {
// console.log('changed')
if ($('.check_delete_bounced:checked').length > 1) {
$('#delete_all_bounced').show()
}
else {
$('#delete_all_bounced').hide()
}
})
$('#delete_all_bounced').click(function (e) {
e.preventDefault()
if (!confirm('Are you sure you want to delete the selected contacts ?')) {
$('#check_all_bounced').prop('checked', false)
$('.check_delete_bounced').prop('checked', false)
$('#delete_all_bounced').hide()
return;
}
$('#delete_all_bounced').attr('disabled', 'disabled')
var selected = [];
$('.check_delete_bounced:checked').each(function () {
selected.push($(this).attr('value'));
// console.log(selected)
});
console.log(selected)
$.ajax({
url: "{% url 'marketing:delete_multiple_contacts' %}",
type: 'POST',
data: {
'selected_list': selected,
'from_contact': "{{contact_list.id}}",
},
success: function (data) {
console.log(data)
if (data['error'] === false) {
window.location.reload()
}
else {
$('#delete_all_bounced').removeAttr('disabled', 'disabled')
alert(data['message'])
}
},
});
})
// $(".remove_account").click(function (e) {
// e.preventDefault()
@ -148,15 +420,18 @@
e.preventDefault()
url = $(this).attr('href')
var contact_lists = parseInt($(this).attr('data-other-contacts-lists'));
if (contact_lists > 1) {
if (!confirm('This contact exists in other contact lists too. Are you sure you want to delete this contact?'))
return;
window.location = $(this).attr('href');
} else {
if (!confirm('Are you sure you want to delete?'))
return;
window.location = $(this).attr('href');
}
// if (contact_lists > 1) {
// if (!confirm('This contact exists in other contact lists too. Are you sure you want to delete this contact?'))
// return;
// window.location = $(this).attr('href');
// } else {
// if (!confirm('Are you sure you want to delete?'))
// return;
// window.location = $(this).attr('href');
// }
if (!confirm('Are you sure you want to delete?'))
return;
window.location = $(this).attr('href');
})
$(".edit_contact").click(function (e) {
@ -173,6 +448,16 @@
$('#leads_filter').attr("action", $(this).attr("href"));
$('#leads_filter').submit();
});
var queryParams = (window.location.search).replace('?', '').split('&').map(param => param.split('=')).reduce((values, [key, value]) => { values[key] = value; return values; }, {})
if (!queryParams.hasOwnProperty('page') && queryParams.hasOwnProperty('bounced_contacts_page')) {
//active the tab
// $('#open-tab').removeClass('active')
// $('#close-tab').addClass('active')
$('#close-tab').trigger('click')
}
})
</script>
{% endblock js_block %}

View file

@ -87,8 +87,9 @@
<th width="5%">S. No</th>
<th width="20%">Name</th>
<th width="10%">No. of Contacts</th>
<th width="20%">Created by</th>
<th width="15%">Last Activity</th>
<th width="15%">No. of Bounced Contacts</th>
<th width="20%" class="text-center">Created by</th>
<th width="10%">Last Activity</th>
<th width="15%" class="text-center">Tags</th>
<th width="10%">Actions</th>
</tr>
@ -104,14 +105,23 @@
<tr style="text-align:center;">
<td scope="row">{{ forloop.counter }}</td>
<td><a href="{% url 'marketing:contact_list_detail' contact_list.id %}">{{ contact_list.name }}</td>
<td class="text-center">{{ contact_list.contacts.count }}</td>
<td>{{ contact_list.created_by }}</td>
<td>
{{ contact_list.updated_on }}
<td class="text-center">
<a href="{% url 'marketing:contact_list_detail' contact_list.id %}">
{{ contact_list.contacts.count }}
</a>
</td>
<td class="text-center">
<a href="{% url 'marketing:contact_list_detail' contact_list.id %}?bounced_contacts_page=1">
{{ contact_list.bounced_contacts }}
</a>
</td>
<td class="text-center">{{ contact_list.created_by }}</td>
<td title="{{ contact_list.updated_on }}">
{{ contact_list.updated_on_arrow }}
</td>
<td class="text-center">
{% for tag in contact_list.tags.all %}
<span class="text-left color{{forloop.counter}} tag_class_camp" id="list_tag">{{tag.name}}</span>
<span class="text-left color{{forloop.counter}} tag_class_camp tag_class_cl" data-link="{{tag.id}}" id="list_tag" style="cursor: pointer;">{{tag.name}}</span>
{% empty %}
<span class="text-center">No Tags!</span>
{% endfor %}
@ -251,6 +261,13 @@
});
$('#id_tag').select2();
$(".tag_class_cl").click(function () {
// $(".tag_class_opp").css('cursor', 'pointer')
url = "{% url 'marketing:contact_lists' %}"
url = url + "?tag=" + $(this).attr('data-link')
window.location.href = url;
})
$("a[rel='page']").click(function (e) {
e.preventDefault();
$('#leads_filter').attr("action", $(this).attr("href"));

View file

@ -49,7 +49,7 @@
</div>
<div class="filter_col col-md-12">
<div class="form-group">
<label>Contacts File <span class="error">*</span>
<label>Contacts File <span class="error">{% if contact_list %}{% else %}*{% endif %}</span>
</label>
<input type="file" class="form-control" name="contacts_file">
<span id="id_contacts_file"></span>

View file

@ -1,5 +1,6 @@
{% extends 'sales/base.html' %}
{% load staticfiles %}
{% load thumbnail %}
{% block content %}
{% load common_tags %}
<!-- <a href="{% url "common:logout" %}"><button class="btn btn-primary" type="button">Logout</button></a> -->
@ -57,9 +58,9 @@
<table class="table">
<thead>
<tr>
<th width="45%">Name</th>
<th width="50%">Tags</th>
<th width="50%">Assigned To</th>
<th width="30%">Name</th>
<th width="30%">Tags</th>
<th width="40%">Assigned To</th>
</tr>
</thead>
<tbody>
@ -82,16 +83,27 @@
<td>
{% with users=account.assigned_to.all %}
{% for user in users|slice:'3' %}
<div>
<a href="{% url 'common:view_user' user.id %}">{{user}}</a>
</div>
{% if user.profile_pic %}
{% thumbnail user.profile_pic "40x40" crop="center" as im %}
<span>
<a href="{% url 'common:view_user' user.id %}">
<img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}"
title="{{ user.email }}">
</a>
{% endthumbnail %}
{% else %}
<a href="{% url 'common:view_user' user.id %}">
<img src="{% static 'images/user.png' %}" title="{{ user.email }}" width="40" height="40">
</a>
</span>
{% endif %}
{% empty %}
<span class="text-left">None</span>
{% endfor %}
{% if users|length > 3 %}
<div>
<a href="{% url 'accounts:view_account' account.id %}">
<span class="text-left" id="list_tag">{{users|length|subtract:'3'}}<span> more
<span class="text-left mt-2" id="list_tag">{{users|length|subtract:'3'}}<span> more
</span></span></a>
</div>
{% endif %}
@ -119,9 +131,9 @@
<table class="table">
<thead>
<tr>
<th width="45%">Name</th>
<th width="50%">Tags</th>
<th width="50%">Assigned To</th>
<th width="30%">Name</th>
<th width="30%">Tags</th>
<th width="40%">Assigned To</th>
</tr>
</thead>
<tbody>
@ -144,17 +156,30 @@
<td>
{% with users=opportunity.assigned_to.all %}
{% for user in users|slice:'3' %}
<span class="text-left" id="list_opp_users_"><a href="{% url 'common:view_user' user.id %}">{{user}}</a><span>
{% empty %}
<span class="text-left">None</span>
{% endfor %}
{% if users|length > 3 %}
<a href="{% url 'opportunity:opp_view' opportunity.id %}">
<span class="text-left" id="list_tag">{{users|length|subtract:'3'}}<span> more
</span></span>
</a>
{% endif %}
{% endwith %}
{% if user.profile_pic %}
{% thumbnail user.profile_pic "40x40" crop="center" as im %}
<span>
<a href="{% url 'common:view_user' user.id %}">
<img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}"
title="{{ user.email }}">
</a>
{% endthumbnail %}
{% else %}
<a href="{% url 'common:view_user' user.id %}">
<img src="{% static 'images/user.png' %}" title="{{ user.email }}" width="40" height="40">
</a>
</span>
{% endif %}
{% empty %}
<span class="text-left">None</span>
{% endfor %}
{% if users|length > 3 %}
<a href="{% url 'opportunity:opp_view' opportunity.id %}">
<span class="text-left mt-2" id="list_tag">{{users|length|subtract:'3'}}<span> more
</span></span>
</a>
{% endif %}
{% endwith %}
</td>
</tr>
{% endfor %}