marketing module and invoicing enhancements
This commit is contained in:
parent
b41b0fe7a1
commit
abcd47f600
33 changed files with 881 additions and 178 deletions
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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 %}
|
||||
|
|
|
|||
|
|
@ -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 -->
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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 %}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@
|
|||
.opacity_block {
|
||||
opacity: 0.2;
|
||||
}
|
||||
.form-group label{
|
||||
font-weight: 800;
|
||||
color:black;
|
||||
}
|
||||
</style>
|
||||
{% endblock extralinks %}
|
||||
<!-- breadcrumb starts here -->
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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') {
|
||||
|
|
|
|||
|
|
@ -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'):
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
0
marketing/templatetags/__init__.py
Normal file
0
marketing/templatetags/__init__.py
Normal file
87
marketing/templatetags/digg_paginator.py
Normal file
87
marketing/templatetags/digg_paginator.py
Normal 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)
|
||||
|
|
@ -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"),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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') {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 %}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
|
|||
46
templates/contact_list_digg_paginator.html
Normal file
46
templates/contact_list_digg_paginator.html
Normal 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 %}
|
||||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 %}
|
||||
|
|
@ -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"));
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 %}
|
||||
|
|
|
|||
Loading…
Reference in a new issue