Implemented tags section in accounts and leads

This commit is contained in:
Ashwin 2019-02-04 14:52:05 +05:30
parent 44696a1bf1
commit 4856531eb7
14 changed files with 284 additions and 14 deletions

View file

@ -0,0 +1,26 @@
# Generated by Django 2.1.5 on 2019-02-01 13:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0002_auto_20190128_1237'),
]
operations = [
migrations.CreateModel(
name='Tags',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=20)),
('slug', models.CharField(blank=True, max_length=20, unique=True)),
],
),
migrations.AddField(
model_name='account',
name='tags',
field=models.ManyToManyField(blank=True, to='accounts.Tags'),
),
]

View file

@ -5,6 +5,17 @@ from django.utils.translation import ugettext_lazy as _
from common.models import User, Address, Team
from common.utils import INDCHOICES
from phonenumber_field.modelfields import PhoneNumberField
from django.utils.text import slugify
class Tags(models.Model):
name = models.CharField(max_length=20)
slug = models.CharField(max_length=20, unique = True, blank=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Tags, self).save(*args, **kwargs)
class Account(models.Model):
@ -21,6 +32,7 @@ class Account(models.Model):
created_by = models.ForeignKey(User, related_name='account_created_by', on_delete=models.CASCADE)
created_on = models.DateTimeField(_("Created on"), auto_now_add=True)
is_active = models.BooleanField(default=False)
tags = models.ManyToManyField(Tags, blank=True)
def __str__(self):
return self.name

View file

@ -50,6 +50,17 @@
</select>
</div>
</div>
<div class="filter_col col-md-12">
<div class="form-group">
<label for="exampleInputEmail1">Tags</label>
<select class="form-control" id="id_tag" name="tag" >
<option value="">--Select Tags--</option>
{% for tag in tags %}
<option value="{{tag.id}}" {% if request.POST.tag %} {% ifequal tag.id request.POST.tag|add:"0" %}selected{% endifequal %}{% endif %} >{{ tag.name }} </option>
{% endfor%}
</select>
</div>
</div>
<div class="filter_col text-center col-12">
<div class="form-group buttons_row">
<button class="btn btn-primary save" type="submit">Search</button>
@ -76,10 +87,11 @@
{% if accounts_list|length > 0 %}
<tr>
<th width="5%">ID</th>
<th width="25%">Name</th>
<th width="20%">Name</th>
<th width="15%">City</th>
<th width="15%">State</th>
<th width="20%">Industry</th>
<th width="15%">Tags</th>
<th width="10%">Actions</th>
</tr>
{% endif %}
@ -97,6 +109,17 @@
<td>{% if each_account.billing_address.city %}{{ each_account.billing_address.city }} {% else %} Not specified {% endif %}</td>
<td>{% if each_account.billing_address.state %}{{ each_account.billing_address.state }} {% else %} Not specified {% endif %}</td>
<td>{% if each_account.industry %}{{ each_account.industry }} {% else %} Not specified {% endif %}</td>
<td style="display: block;">
{% with tags=each_account.tags.all %}
{% if tags %}
{% for tag in tags %}
<span class="text-left" id="list_tag">{{ tag.name }}</span>
{% endfor %}
{% else %}
No Tags
{% endif %}
{% endwith %}
</td>
<td class="actions">
{# <a href="{% url 'accounts:view_account' each_account.id %}" class="btn btn-info view"><i class="fas fa-eye"></i> View</a> #}
<a href="{% url 'accounts:edit_account' each_account.id %}" class="btn btn-success edit"><i class="fas fa-pencil-alt"></i></a>

View file

@ -13,6 +13,12 @@
{% endblock %}
{% block content %}
<head>
<link rel="stylesheet" type="text/css" href="//xoxco.com/projects/code/tagsinput/jquery.tagsinput.css" />
<script type="text/javascript" src="//xoxco.com/projects/code/tagsinput/jquery.tagsinput.js"></script>
<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js'></script>
<link rel="stylesheet" type="text/css" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/themes/start/jquery-ui.css" />
</head>
<form id="formid" action='' method="POST" novalidate>
<div class="overview_form_block row marl ">
<div class="col-md-12">
@ -107,7 +113,14 @@
</div>
</div>
</div>
<div>
<div class="filter_col col-12">
<div class="form-group">
<label>Tags</label>
<div class="txt-box-div" id="tag-div"><input type="text" name="tags" id="tags_1" value="{% for t in account_obj.tags.all %}{{t.name}}, {% endfor %}" class="tags"/>
</div>
</div>
</div>
<div>
<h6 style="color:white;">Copy Address</h6>
</div>
</div>
@ -131,6 +144,8 @@
{% endblock %}
{% block js_block %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-tagsinput/1.3.6/jquery.tagsinput.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-tagsinput/1.3.6/jquery.tagsinput.min.js"></script>
<script type="text/javascript">
$("#copy_billing_btn").click(function(){
var address_line = $("#id_address_line").val()
@ -155,5 +170,47 @@
$(document).ready(function() {
$('.assigned_users').select2();
});
function onAddTag(tag) {
alert("Added a tag: " + tag);
}
function onRemoveTag(tag) {
alert("Removed a tag: " + tag);
}
function onChangeTag(input,tag) {
alert("Changed a tag: " + tag);
}
$(function() {
$('#tags_1').tagsInput({width:'auto'});
$('#tags_2').tagsInput({
width: 'auto',
onChange: function(elem, elem_tags)
{
var languages = ['php','ruby','javascript'];
$('.tag', elem_tags).each(function()
{
if($(this).text().search(new RegExp('\\b(' + languages.join('|') + ')\\b')) >= 0)
$(this).css('background-color', 'yellow');
});
}
});
$('#tags_3').tagsInput({
width: 'auto',
//autocomplete_url:'test/fake_plaintext_endpoint.html' //jquery.autocomplete (not jquery ui)
autocomplete_url:'test/fake_json_endpoint.html' // jquery ui autocomplete requires a json endpoint
});
// Uncomment this line to see the callback functions in action
// $('input.tags').tagsInput({onAddTag:onAddTag,onRemoveTag:onRemoveTag,onChange: onChangeTag});
// Uncomment this line to see an input with no interface for adding new tags.
// $('input.tags').tagsInput({interactive:false});
});
</script>
{% endblock js_block %}

View file

@ -8,7 +8,7 @@ from django.template.loader import render_to_string
from django.views.generic import (
CreateView, UpdateView, DetailView, TemplateView, View, DeleteView)
from accounts.forms import AccountForm, AccountCommentForm, AccountAttachmentForm
from accounts.models import Account
from accounts.models import Account, Tags
from common.models import User, Address, Team, Comment, Attachments
from common.utils import INDCHOICES, COUNTRIES, CURRENCY_CODES, CASE_TYPE, PRIORITY_CHOICE, STATUS_CHOICE
from contacts.models import Contact
@ -34,6 +34,8 @@ class AccountsListView(LoginRequiredMixin, TemplateView):
city__contains=request_post.get('city'))])
if request_post.get('industry'):
queryset = queryset.filter(industry__icontains=request_post.get('industry'))
if request_post.get('tag'):
queryset = queryset.filter(tags__in=request_post.get('tag'))
return queryset
def get_context_data(self, **kwargs):
@ -41,6 +43,7 @@ class AccountsListView(LoginRequiredMixin, TemplateView):
context["accounts_list"] = self.get_queryset()
context["industries"] = INDCHOICES
context["per_page"] = self.request.POST.get('per_page')
context['tags'] = Tags.objects.all()
return context
def get(self, request, *args, **kwargs):
@ -103,6 +106,16 @@ class CreateAccountView(LoginRequiredMixin, CreateView):
email.send()
if self.request.POST.getlist('teams', []):
account_object.teams.add(*self.request.POST.getlist('teams'))
if self.request.POST.get('tags', ''):
tags = self.request.POST.get("tags")
splitted_tags = tags.split(",")
for t in splitted_tags:
tag = Tags.objects.filter(name=t.lower())
if tag:
tag = tag[0]
else:
tag = Tags.objects.create(name=t.lower())
account_object.tags.add(tag)
if self.request.POST.get("savenewform"):
return redirect("accounts:new_account")
else:
@ -242,6 +255,17 @@ class AccountUpdateView(LoginRequiredMixin, UpdateView):
account_object.assigned_to.add(*self.request.POST.getlist('assigned_to'))
if self.request.POST.getlist('teams', []):
account_object.teams.add(*self.request.POST.getlist('teams'))
account_object.tags.clear()
if self.request.POST.get('tags', ''):
tags = self.request.POST.get("tags")
splitted_tags = tags.split(",")
for t in splitted_tags:
tag = Tags.objects.filter(name=t.lower())
if tag:
tag = tag[0]
else:
tag = Tags.objects.create(name=t.lower())
account_object.tags.add(tag)
return redirect("accounts:list")
def form_invalid(self, form, billing_form, shipping_form):

View file

@ -79,7 +79,7 @@
<div class="filter_col col-md-12">
<div class="form-group">
<label for="id_account">Account{% if case_form.account.field.required %}<span class="error">*</span>{% endif %}</label>
{{ case_form.account }}
<input type="text" name="account" class="form-control" readonly="">
<span class="error">{{case_form.account.errors}}</span>
</div>
</div>

View file

@ -41,7 +41,7 @@
<div class="filter_col col-md-12">
<div class="form-group">
<label for="exampleInputEmail1">Account{% if contact_form.account.field.required %}<span class="error">*</span>{% endif %}</label>
{{ contact_form.account }}
<input type="text" name="account" class="form-control" readonly="">
<span class="error">{{ contact_form.account.errors }}</span>
</div>
</div>

View file

@ -0,0 +1,19 @@
# Generated by Django 2.1.5 on 2019-02-01 13:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0003_auto_20190201_1840'),
('leads', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='lead',
name='tags',
field=models.ManyToManyField(blank=True, to='accounts.Tags'),
),
]

View file

@ -6,6 +6,7 @@ from accounts.models import Account
from common.models import User, Address, Team
from common.utils import LEAD_STATUS, LEAD_SOURCE
from phonenumber_field.modelfields import PhoneNumberField
from accounts.models import Tags
class Lead(models.Model):
@ -34,6 +35,7 @@ class Lead(models.Model):
created_on = models.DateTimeField(_("Created on"), auto_now_add=True)
is_active = models.BooleanField(default=False)
enquery_type = models.CharField(max_length=255, blank=True, null=True)
tags = models.ManyToManyField(Tags, blank=True)
class Meta:
ordering =['-created_on']

View file

@ -13,6 +13,12 @@
{% endblock %}
{%block content%}
<head>
<link rel="stylesheet" type="text/css" href="//xoxco.com/projects/code/tagsinput/jquery.tagsinput.css" />
<script type="text/javascript" src="//xoxco.com/projects/code/tagsinput/jquery.tagsinput.js"></script>
<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js'></script>
<link rel="stylesheet" type="text/css" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/themes/start/jquery-ui.css" />
</head>
<form id="add_form" method="POST" action="" novalidate>
<div class="overview_form_block row marl">
<div class="col-md-12">
@ -132,9 +138,15 @@
</div>
</div>
</div>
<div class="filter_col col-12">
<div class="form-group">
<label>Tags</label>
<div class="txt-box-div" id="tag-div"><input type="text" name="tags" id="tags_1" value="{% for t in lead_obj.tags.all %}{{t.name}}, {% endfor %}" class="tags"/>
</div>
</div>
</div>
</div>
<div class="filter_col col-md-12">
<div class="filter_col col-md-6">
<div class="form-group col-md-12">
<label for="exampleInputEmail1" >Description{% if lead_form.description.field.required %}<span class="error">*</span>{% endif %}</label>
{{ lead_form.description }}
@ -159,6 +171,8 @@
{% endblock %}
{% block js_block %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-tagsinput/1.3.6/jquery.tagsinput.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-tagsinput/1.3.6/jquery.tagsinput.min.js"></script>
<script type="text/javascript">
$(".savenew").on('click', function(e){
e.preventDefault()
@ -168,5 +182,35 @@
$(document).ready(function() {
$('.assigned_users').select2();
});
$(function() {
$('#tags_1').tagsInput({width:'auto'});
$('#tags_2').tagsInput({
width: 'auto',
onChange: function(elem, elem_tags)
{
var languages = ['php','ruby','javascript'];
$('.tag', elem_tags).each(function()
{
if($(this).text().search(new RegExp('\\b(' + languages.join('|') + ')\\b')) >= 0)
$(this).css('background-color', 'yellow');
});
}
});
$('#tags_3').tagsInput({
width: 'auto',
//autocomplete_url:'test/fake_plaintext_endpoint.html' //jquery.autocomplete (not jquery ui)
autocomplete_url:'test/fake_json_endpoint.html' // jquery ui autocomplete requires a json endpoint
});
// Uncomment this line to see the callback functions in action
// $('input.tags').tagsInput({onAddTag:onAddTag,onRemoveTag:onRemoveTag,onChange: onChangeTag});
// Uncomment this line to see an input with no interface for adding new tags.
// $('input.tags').tagsInput({interactive:false});
});
</script>
{% endblock js_block %}

View file

@ -51,6 +51,17 @@
</select>
</div>
</div>
<div class="filter_col col-md-12">
<div class="form-group">
<label for="exampleInputEmail1">Tags</label>
<select class="form-control" id="id_tag" name="tag" >
<option value="">--Select Tags--</option>
{% for tag in tags %}
<option value="{{tag.id}}" {% if request.POST.tag %} {% ifequal tag.id request.POST.tag|add:"0" %}selected{% endifequal %}{% endif %} >{{ tag.name }} </option>
{% endfor%}
</select>
</div>
</div>
<div class="filter_col text-center col-12">
<div class="form-group buttons_row">
<button class="btn btn-primary save" type="submit">Search</button>
@ -80,10 +91,11 @@
{% if lead_obj|length > 0 %}
<tr>
<th width="5%">ID</th>
<th width="25%" >Name</th>
<th width="15%" >Status</th>
<th width="15%" >Assigned User</th>
<th width="20%" >Created On</th>
<th width="20%" >Name</th>
<th width="5%" >Status</th>
<th width="20%" >Assigned User</th>
<th width="25%" >Tags</th>
<th width="15%" >Created On</th>
<th width="10%" >Actions</th>
</tr>
{% endif %}
@ -110,6 +122,17 @@
{% endif %}
{% endwith %}
</td>
<td style="display: block;">
{% with tags=lead.tags.all %}
{% if tags %}
{% for tag in tags %}
<span class="text-left" id="list_tag">{{ tag.name }}</span><br>
{% endfor %}
{% else %}
No Tags
{% endif %}
{% endwith %}
</td>
<td>{{ lead.created_on }}</td>
<td class="actions">
{# <a href="{% url 'leads:view_lead' lead.id %}" class="btn btn-info view"><i class="fas fa-eye"></i> </a> #}

View file

@ -11,7 +11,7 @@ from django.urls import reverse
from django.views.generic import (
CreateView, UpdateView, DetailView, ListView, TemplateView, View)
from accounts.models import Account
from accounts.models import Account, Tags
from common.forms import BillingAddressForm
from common.models import User, Comment, Team, Attachments
from common.utils import LEAD_STATUS, LEAD_SOURCE, COUNTRIES
@ -40,6 +40,8 @@ class LeadListView(LoginRequiredMixin, TemplateView):
queryset = queryset.filter(email__icontains=request_post.get('email'))
if request_post.get('status'):
queryset = queryset.filter(status=request_post.get('status'))
if request_post.get('tag'):
queryset = queryset.filter(tags__in=request_post.get('tag'))
return queryset
def get_context_data(self, **kwargs):
@ -47,6 +49,7 @@ class LeadListView(LoginRequiredMixin, TemplateView):
context["lead_obj"] = self.get_queryset()
context["status"] = LEAD_STATUS
context["per_page"] = self.request.POST.get('per_page')
context['tags'] = Tags.objects.all()
return context
def post(self, request, *args, **kwargs):
@ -83,6 +86,16 @@ class CreateLeadView(LoginRequiredMixin, CreateView):
lead_obj.address = address_object
lead_obj.created_by = self.request.user
lead_obj.save()
if self.request.POST.get('tags', ''):
tags = self.request.POST.get("tags")
splitted_tags = tags.split(",")
for t in splitted_tags:
tag = Tags.objects.filter(name=t)
if tag:
tag = tag[0]
else:
tag = Tags.objects.create(name=t)
lead_obj.tags.add(tag)
if self.request.POST.getlist('assigned_to', []):
lead_obj.assigned_to.add(*self.request.POST.getlist('assigned_to'))
assigned_to_list = self.request.POST.getlist('assigned_to')
@ -105,9 +118,12 @@ class CreateLeadView(LoginRequiredMixin, CreateView):
created_by=self.request.user, name=lead_obj.account_name,
email=lead_obj.email, phone=lead_obj.phone,
description=self.request.POST.get('description'),
website=self.request.POST.get('website')
website=self.request.POST.get('website'),
)
account_object.billing_address = address_object
for tag in lead_obj.tags.all():
account_object.tags.add(tag)
account_object.tags.add(address_object)
if self.request.POST.getlist('assigned_to', []):
account_object.assigned_to.add(*self.request.POST.getlist('assigned_to'))
assigned_to_list = self.request.POST.getlist('assigned_to')
@ -244,7 +260,18 @@ class UpdateLeadView(LoginRequiredMixin, UpdateView):
lead_obj.address = address_obj
lead_obj.save()
lead_obj.teams.clear()
lead_obj.tags.clear()
all_members_list = []
if self.request.POST.get('tags', ''):
tags = self.request.POST.get("tags")
splitted_tags = tags.split(",")
for t in splitted_tags:
tag = Tags.objects.filter(name=t)
if tag:
tag = tag[0]
else:
tag = Tags.objects.create(name=t)
lead_obj.tags.add(tag)
if self.request.POST.getlist('assigned_to', []):
if self.request.POST.get('status') != "converted":
@ -278,6 +305,8 @@ class UpdateLeadView(LoginRequiredMixin, UpdateView):
website=self.request.POST.get('website')
)
account_object.billing_address = address_obj
for tag in lead_obj.tags.all():
account_object.tags.add(tag)
if self.request.POST.getlist('assigned_to', []):
account_object.assigned_to.add(*self.request.POST.getlist('assigned_to'))
assigned_to_list = self.request.POST.getlist('assigned_to')

View file

@ -32,7 +32,7 @@
<div class="filter_col col-md-12">
<div class="form-group">
<label for="exampleInputEmail1">Account{% if opportunity_form.account.field.required %}<span class="error">*</span>{% endif %}</label>
{{ opportunity_form.account }}
<input type="text" name="account" class="form-control" readonly="">
<span class="error">{{opportunity_form.account.errors}}</span>
</div>
</div>

View file

@ -806,3 +806,14 @@ padding:0px !important;
padding:3px 10px;
border-radius: 3px;
}
#list_tag{
background: #e5e5e5;
color: #000;
font-weight: 500;
padding: 1px 5px;
margin-right: 5px;
font-size: 0.9rem;
display: inline-block;
margin-bottom: 5px;
}