Merge pull request #184 from MicroPyramid/dev

enhanced UI
This commit is contained in:
Ashwin Kumar 2019-02-06 22:31:09 +05:30 committed by GitHub
commit 646dfefdda
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 574 additions and 445 deletions

View file

@ -1,26 +0,0 @@
Python 3.4:
script:
- export PY_EXE=python3.4
- virtualenv -p python3 env
- source env/bin/activate
- pip install -r requirements.txt
- python manage.py test --noinput
- coverage run --source=accounts,cases,common,contacts,emails,leads,opportunity,planner manage.py test --noinput
- coverage report -m
except:
- tags
deploy_live:
stage: deploy
environment:
name: live
script:
- sudo /bin/rm -rf /home/dj_crm/dj_crm/; cp -r . /home/dj_crm/dj_crm
- source /home/dj_crm/env/bin/activate
- pip install -r /home/dj_crm/dj_crm/requirements.txt
- python /home/dj_crm/dj_crm/manage.py migrate --noinput
- sudo /etc/init.d/uwsgi restart
only:
- master
tags:
- github-crm

View file

@ -1,6 +1,9 @@
{% extends 'base.html' %}
{% load staticfiles %}
{% load paginate %}
{% block extralinks %}
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
{% endblock %}
{% block content %}
<!-- main_container starts here -->
<div class="main_container">
@ -33,10 +36,9 @@
<div class="filter_col col-md-2">
<div class="form-group">
<label for="exampleInputEmail1">Assigned Users</label>
{{request.POST.assigned_to}}
<select class="assigned_users1 form-control" name="assigned_to" multiple="multiple">
<select class="assigned_users form-control" name="assigned_to" multiple="multiple">
{% for user in users %}
<option value="{{user.id}}" {% if user in account_obj.assigned_to.all or user.id in assignedto_list %} selected="" {% endif %}>{{user.email}}</option>
<option value="{{user.id}}" {% if user in account_obj.assigned_to.all or user.id in assignedto_list or user.id in request.POST.assigned_to %} selected="" {% endif %}>{{user.email}}</option>
{% endfor %}
</select>
{{ account_form.assigned_to.errors }}
@ -98,7 +100,7 @@
<div class="card-body">
<div class="panel-heading-list card-title text-right">
<span class="total_count float-left">List of Open Accounts :{% if show_pageitems %} {% show_pageitems %}{% else %}{{open_accounts|length}}{% endif %}</span>
<span class="total_count float-left">Open Accounts - {% if show_pageitems %} {% show_pageitems %}{% else %}{{open_accounts|length}}{% endif %}</span>
<span class="filter_toggle ">
<a href="#" class="primary_btn"><i class="fas fa-filter"></i></a>
</span>
@ -131,7 +133,17 @@
<td>{% if each_account.name %}<a href="{% url 'accounts:view_account' each_account.id %}">{{ each_account.name }}</a>{% endif %}</td>
<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>santro@mp.com</td>
<td>
{% with assigned_users=each_account.assigned_to.all %}
{% if assigned_users %}
{% for user in assigned_users %}
<span class="text-left">{{ user.email }}</span><br>
{% endfor %}
{% else %}
Not Assigned
{% endif %}
{% endwith %}
</td>
<td>{% if each_account.industry %}{{ each_account.industry }} {% else %} Not specified {% endif %}</td>
<td style="display: block;">
{% with tags=each_account.tags.all %}
@ -166,9 +178,11 @@
<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">
List of Closed Accounts
<span class="float-right total_count">{% if show_pageitems %} {% show_pageitems %}{% else %}Total Closed Accounts {{close_accounts|length}}{% endif %}</span>
<div class="panel-heading-list card-title text-right">
<span class="total_count float-left">Close Accounts - {% if show_pageitems %} {% show_pageitems %}{% else %}{{close_accounts|length}}{% endif %}</span>
<span class="filter_toggle ">
<a href="#" class="primary_btn"><i class="fas fa-filter"></i></a>
</span>
</div>
<div class="table-responsive">
<table class="table">
@ -177,11 +191,11 @@
<tr>
<th width="5%">ID</th>
<th width="15%">Name</th>
<th width="15%">City</th>
<th width="15%">State</th>
<th width="15%">Assigned To</th>
<th width="15%">Industry</th>
<th width="10%">Tags</th>
<th width="10%">City</th>
<th width="10%">State</th>
<th width="25%">Assigned To</th>
<th width="10%">Industry</th>
<th width="20%">Tags</th>
<th width="10%">Actions</th>
</tr>
{% endif %}
@ -198,7 +212,17 @@
<td>{% if each_account.name %}<a href="{% url 'accounts:view_account' each_account.id %}">{{ each_account.name }}</a>{% endif %}</td>
<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>santro@mp.com</td>
<td>
{% with assigned_users=each_account.assigned_to.all %}
{% if assigned_users %}
{% for user in assigned_users %}
<span class="text-left">{{ user.email }}</span><br>
{% endfor %}
{% else %}
Not Assigned
{% endif %}
{% endwith %}
</td>
<td>{% if each_account.industry %}{{ each_account.industry }} {% else %} Not specified {% endif %}</td>
<td style="display: block;">
{% with tags=each_account.tags.all %}
@ -242,7 +266,12 @@
<!-- main_container ends here -->
{% endblock %}
{% block js_block %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/js/select2.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('.assigned_users').select2();
});
$('.remove_account').click(function(e){
e.preventDefault()
url = $(this).attr('href')
@ -259,7 +288,6 @@
$(".filter_toggle").click(function(){
$(".list_filter_row").toggle();
});
$('.assigned_users1').select2();
});
$("a[rel='page']").click(function(e){

View file

@ -121,7 +121,7 @@
<div class="col-md-12">
<div class="row marl buttons_row form_btn_row text-center">
<button class="btn btn-default save" type="submit">Save</button>
<a href="{% if not user_obj or request.user.is_superuser or request.user.role == 'ADMIN' %}{% url 'common:users_list' %}{% else %}{% url 'common:profile' %}{% endif %}" class="btn btn-default clear" id="create_user_cancel">Cancel</a>
<a href="{% url 'accounts:list' %}" class="btn btn-default clear" id="create_user_cancel">Cancel</a>
</div>
</div>

View file

@ -130,6 +130,18 @@
</div>
</div>
{% endif %}
{% if account_record.tags.all %}
<div class="filter_col col-md-12">
<div class="form-group">
<label class="acc_field_label" for="id_tags" data-name="name">Tags</label>
<div class="account_field" id="account_tags" data-name="name">
{% for tag in account_record.tags.all %}
<span class="text-left" id="list_tag">{{ tag.name }}</span>
{% endfor %}
</div>
</div>
</div>
{% endif %}
</div>
<div class="col-md-12">
<div class="created_information">

View file

@ -44,6 +44,7 @@ class AccountsListView(LoginRequiredMixin, TemplateView):
open_accounts = self.get_queryset().filter(status='open')
close_accounts = self.get_queryset().filter(status='close')
context["accounts_list"] = self.get_queryset()
context["users"] = User.objects.filter(is_active=True).order_by('email')
context['open_accounts'] = open_accounts
context['close_accounts'] = close_accounts
context["industries"] = INDCHOICES
@ -81,8 +82,8 @@ class CreateAccountView(LoginRequiredMixin, CreateView):
shipping_form = ShippingAddressForm(request.POST, prefix='ship')
if form.is_valid() and billing_form.is_valid() and shipping_form.is_valid():
return self.form_valid(form, billing_form, shipping_form)
else:
return self.form_invalid(form, billing_form, shipping_form)
return self.form_invalid(form, billing_form, shipping_form)
def form_valid(self, form, billing_form, shipping_form):
# Save Billing & Shipping Address
@ -112,19 +113,19 @@ class CreateAccountView(LoginRequiredMixin, CreateView):
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)
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:
return redirect("accounts:list")
return redirect("accounts:list")
def form_invalid(self, form, billing_form, shipping_form):
return self.render_to_response(
@ -222,8 +223,8 @@ class AccountUpdateView(LoginRequiredMixin, UpdateView):
request.POST, instance=self.object.shipping_address, prefix='ship')
if form.is_valid() and billing_form.is_valid() and shipping_form.is_valid():
return self.form_valid(form, billing_form, shipping_form)
else:
return self.form_invalid(form, billing_form, shipping_form)
return self.form_invalid(form, billing_form, shipping_form)
def form_valid(self, form, billing_form, shipping_form):
assigned_to_ids = self.get_object().assigned_to.all().values_list('id', flat=True)
@ -340,11 +341,11 @@ class AddCommentView(LoginRequiredMixin, CreateView):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
else:
data = {'error': "You don't have permission to comment for this account."}
return JsonResponse(data)
return self.form_invalid(form)
data = {'error': "You don't have permission to comment for this account."}
return JsonResponse(data)
def form_valid(self, form):
comment = form.save(commit=False)
@ -370,11 +371,11 @@ class UpdateCommentView(LoginRequiredMixin, View):
form = AccountCommentForm(request.POST, instance=self.comment_obj)
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
else:
data = {'error': "You don't have permission to edit this comment."}
return JsonResponse(data)
return self.form_invalid(form)
data = {'error': "You don't have permission to edit this comment."}
return JsonResponse(data)
def form_valid(self, form):
self.comment_obj.comment = form.cleaned_data.get("comment")
@ -396,9 +397,9 @@ class DeleteCommentView(LoginRequiredMixin, View):
self.object.delete()
data = {"cid": request.POST.get("comment_id")}
return JsonResponse(data)
else:
data = {'error': "You don't have permission to delete this comment."}
return JsonResponse(data)
data = {'error': "You don't have permission to delete this comment."}
return JsonResponse(data)
class AddAttachmentView(LoginRequiredMixin, CreateView):
@ -417,11 +418,11 @@ class AddAttachmentView(LoginRequiredMixin, CreateView):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
else:
data = {'error': "You don't have permission to add attachment for this account."}
return JsonResponse(data)
return self.form_invalid(form)
data = {'error': "You don't have permission to add attachment for this account."}
return JsonResponse(data)
def form_valid(self, form):
attachment = form.save(commit=False)
@ -447,11 +448,13 @@ class DeleteAttachmentsView(LoginRequiredMixin, View):
def post(self, request, *args, **kwargs):
self.object = get_object_or_404(Attachments, id=request.POST.get("attachment_id"))
if (request.user == self.object.created_by or request.user.is_superuser or
request.user.role == 'ADMIN'):
if (
request.user == self.object.created_by or request.user.is_superuser or
request.user.role == 'ADMIN'
):
self.object.delete()
data = {"acd": request.POST.get("attachment_id")}
return JsonResponse(data)
else:
data = {'error': "You don't have permission to delete this attachment."}
return JsonResponse(data)
data = {'error': "You don't have permission to delete this attachment."}
return JsonResponse(data)

View file

@ -34,7 +34,8 @@ class CaseForm(forms.ModelForm):
case = Case.objects.filter(name__iexact=name).exclude(id=self.instance.id)
if case:
raise forms.ValidationError("Case Already Exists with this Name")
return name
else:
return name
class CaseCommentForm(forms.ModelForm):

View file

@ -81,7 +81,7 @@
<div class="card-body">
<div class="panel-heading-list card-title text-right">
<span class="total_count float-left">Total Cases :{% if show_pageitems %} {% show_pageitems %}{% else %}Total Cases {{ cases|length }}{% endif %}</span>
<span class="total_count float-left">Cases - {% if show_pageitems %} {% show_pageitems %}{% else %}{{ cases|length }}{% endif %}</span>
<span class="filter_toggle ">
<a href="#" class="primary_btn"><i class="fas fa-filter"></i></a>
</span>

View file

@ -111,7 +111,7 @@
{% if not case_obj %}
<button class="btn btn-success save savenew" type="submit">Save & New</button>
{% endif %}
<a {% if request.GET.view_account %} href="{% url 'accounts:view_account' request.GET.view_account %}" {% else %} href="{% url 'contacts:list' %}" {% endif %} class="btn btn-default clear">Cancel</a>
<a {% if request.GET.view_account %} href="{% url 'accounts:view_account' request.GET.view_account %}" {% else %} href="{% url 'cases:list' %}" {% endif %} class="btn btn-default clear">Cancel</a>
</div>
</div>
</div>

View file

@ -77,8 +77,8 @@ class CreateCaseView(LoginRequiredMixin, CreateView):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
return self.form_invalid(form)
def form_valid(self, form):
case = form.save(commit=False)
@ -110,8 +110,8 @@ class CreateCaseView(LoginRequiredMixin, CreateView):
if self.request.POST.get('from_account'):
from_account = self.request.POST.get('from_account')
return redirect("accounts:view_account", pk=from_account)
else:
return redirect('cases:list')
return redirect('cases:list')
def form_invalid(self, form):
if self.request.is_ajax():
@ -183,8 +183,8 @@ class UpdateCaseView(LoginRequiredMixin, UpdateView):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
return self.form_invalid(form)
def form_valid(self, form):
assigned_to_ids = self.get_object().assigned_to.all().values_list('id', flat=True)
@ -263,8 +263,8 @@ class RemoveCaseView(LoginRequiredMixin, View):
if request.GET.get('view_account'):
account = request.GET.get('view_account')
return redirect("accounts:view_account", pk=account)
else:
return redirect("cases:list")
return redirect("cases:list")
def post(self, request, *args, **kwargs):
case_id = kwargs.get("case_id")
@ -324,11 +324,11 @@ class AddCommentView(LoginRequiredMixin, CreateView):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
else:
data = {'error': "You don't have permission to comment."}
return JsonResponse(data)
return self.form_invalid(form)
data = {'error': "You don't have permission to comment."}
return JsonResponse(data)
def form_valid(self, form):
comment = form.save(commit=False)
@ -350,16 +350,18 @@ class UpdateCommentView(LoginRequiredMixin, View):
def post(self, request, *args, **kwargs):
self.comment_obj = get_object_or_404(Comment, id=request.POST.get("commentid"))
if (request.user == self.comment_obj.commented_by or request.user.is_superuser or
request.user.role == 'ADMIN'):
if (
request.user == self.comment_obj.commented_by or request.user.is_superuser or
request.user.role == 'ADMIN'
):
form = CaseCommentForm(request.POST, instance=self.comment_obj)
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
else:
data = {'error': "You don't have permission to edit this comment."}
return JsonResponse(data)
return self.form_invalid(form)
data = {'error': "You don't have permission to edit this comment."}
return JsonResponse(data)
def form_valid(self, form):
self.comment_obj.comment = form.cleaned_data.get("comment")
@ -377,14 +379,16 @@ class DeleteCommentView(LoginRequiredMixin, View):
def post(self, request, *args, **kwargs):
self.object = get_object_or_404(Comment, id=request.POST.get("comment_id"))
if (request.user == self.object.commented_by or request.user.is_superuser or
request.user.role == 'ADMIN'):
if (
request.user == self.object.commented_by or request.user.is_superuser or
request.user.role == 'ADMIN'
):
self.object.delete()
data = {"cid": request.POST.get("comment_id")}
return JsonResponse(data)
else:
data = {'error': "You don't have permission to delete this comment."}
return JsonResponse(data)
data = {'error': "You don't have permission to delete this comment."}
return JsonResponse(data)
class AddAttachmentView(LoginRequiredMixin, CreateView):
@ -403,11 +407,11 @@ class AddAttachmentView(LoginRequiredMixin, CreateView):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
else:
data = {"error":True, "errors": "You don't have permission to add attachment for this case."}
return JsonResponse(data)
return self.form_invalid(form)
data = {"error":True, "errors": "You don't have permission to add attachment for this case."}
return JsonResponse(data)
def form_valid(self, form):
attachment = form.save(commit=False)
@ -437,11 +441,13 @@ class DeleteAttachmentsView(LoginRequiredMixin, View):
def post(self, request, *args, **kwargs):
self.object = get_object_or_404(Attachments, id=request.POST.get("attachment_id"))
if (request.user == self.object.created_by or request.user.is_superuser or
request.user.role == 'ADMIN'):
if (
request.user == self.object.created_by or request.user.is_superuser or
request.user.role == 'ADMIN'
):
self.object.delete()
data = {"attachment_object": request.POST.get("attachment_id"), "error": False}
return JsonResponse(data)
else:
data = {"error":True, "errors": "You don't have permission to delete this attachment."}
return JsonResponse(data)
data = {"error":True, "errors": "You don't have permission to delete this attachment."}
return JsonResponse(data)

View file

@ -6,4 +6,4 @@ admin.site.register(User)
admin.site.register(Address)
admin.site.register(Team)
admin.site.register(Comment)
admin.site.register(Comment_Files)
admin.site.register(Comment_Files)

View file

@ -81,15 +81,13 @@ class UserForm(forms.ModelForm):
if self.instance.email != email:
if not User.objects.filter(email=self.cleaned_data.get("email")).exists():
return self.cleaned_data.get("email")
else:
raise forms.ValidationError('Email already exists')
raise forms.ValidationError('Email already exists')
else:
return self.cleaned_data.get("email")
else:
if not User.objects.filter(email=self.cleaned_data.get("email")).exists():
return self.cleaned_data.get("email")
else:
raise forms.ValidationError('User already exists with this email')
return self.cleaned_data.get("email")
raise forms.ValidationError('User already exists with this email')
class LoginForm(forms.ModelForm):

View file

@ -1,10 +1,9 @@
from django.db import models
from datetime import datetime
from django.template.defaultfilters import slugify
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, UserManager
from common.templatetags.common_tags import *
from common.templatetags.common_tags import (is_document_file_image,is_document_file_audio,
is_document_file_video,is_document_file_pdf,is_document_file_code,is_document_file_text,
is_document_file_sheet,is_document_file_zip)
from common.utils import COUNTRIES, ROLES
import time
@ -118,8 +117,8 @@ class Comment_Files(models.Model):
def get_file_name(self):
if self.comment_file:
return self.comment_file.path.split('/')[-1]
else:
return None
return None
class Attachments(models.Model):
@ -140,19 +139,19 @@ class Attachments(models.Model):
ext = name_ext_list[int(len(name_ext_list) - 1)]
if is_document_file_audio(ext):
return ("audio", "fa fa-file-audio")
elif is_document_file_video(ext):
if is_document_file_video(ext):
return ("video", "fa fa-file-video")
elif is_document_file_image(ext):
if is_document_file_image(ext):
return ("image", "fa fa-file-image")
elif is_document_file_pdf(ext):
if is_document_file_pdf(ext):
return ("pdf", "fa fa-file-pdf")
elif is_document_file_code(ext):
if is_document_file_code(ext):
return ("code", "fa fa-file-code")
elif is_document_file_text(ext):
if is_document_file_text(ext):
return ("text", "fa fa-file-alt")
elif is_document_file_sheet(ext):
if is_document_file_sheet(ext):
return ("sheet", "fa fa-file-excel")
elif is_document_file_zip(ext):
if is_document_file_zip(ext):
return ("zip", "fa fa-file-archive")
return ("file", "fa fa-file")
return ("file", "fa fa-file")
@ -189,19 +188,19 @@ class Document(models.Model):
ext = name_ext_list[int(len(name_ext_list) - 1)]
if is_document_file_audio(ext):
return ("audio", "fa fa-file-audio")
elif is_document_file_video(ext):
if is_document_file_video(ext):
return ("video", "fa fa-file-video")
elif is_document_file_image(ext):
if is_document_file_image(ext):
return ("image", "fa fa-file-image")
elif is_document_file_pdf(ext):
if is_document_file_pdf(ext):
return ("pdf", "fa fa-file-pdf")
elif is_document_file_code(ext):
if is_document_file_code(ext):
return ("code", "fa fa-file-code")
elif is_document_file_text(ext):
if is_document_file_text(ext):
return ("text", "fa fa-file-alt")
elif is_document_file_sheet(ext):
if is_document_file_sheet(ext):
return ("sheet", "fa fa-file-excel")
elif is_document_file_zip(ext):
if is_document_file_zip(ext):
return ("zip", "fa fa-file-archive")
return ("file", "fa fa-file")
return ("file", "fa fa-file")

View file

@ -55,7 +55,7 @@
<div class="card">
<div class="card-body">
<div class="panel-heading-list card-title text-right">
<span class="total_count float-left">Documents :{% if show_pageitems %} {% show_pageitems %}{% else %}Total Documents {{documents|length}}{% endif %}</span>
<span class="total_count float-left">Documents - {% if show_pageitems %} {% show_pageitems %}{% else %} {{documents|length}}{% endif %}</span>
<span class="filter_toggle ">
<a href="#" class="primary_btn"><i class="fas fa-filter"></i></a>
</span>
@ -116,7 +116,7 @@
<script type="text/javascript">
$(document).ready(function(){
$(".filter_toggle").click(function(){
$(".filter_toggle").click(function(){
$(".list_filter_row").toggle();
});
});
@ -129,11 +129,6 @@
window.location = $(this).attr('href')
});
$(document).ready(function(){
$(".filter_toggle").click(function(){
$(".list_filter_row").toggle();
});
});
$(".reset").click(function(e){
window.location = "{% url 'common:doc_list'%}"
});

View file

@ -110,3 +110,7 @@ def is_document_file_zip(ext):
ext_list = ['zip', '7Z', 'gz', 'rar', 'ZIPX', 'ACE', 'tar', ]
return ext.lower() in ext_list
@register.filter
def subtract(value, arg):
return value - int(arg)

View file

@ -1,6 +1,6 @@
from django.contrib.auth import views as auth_views
from django.urls import path, re_path
from django.urls import path
from common.views import (
HomeView, LoginView, ForgotPasswordView, LogoutView, ChangePasswordView, ProfileView,
UsersListView, CreateUserView, UpdateUserView, UserDetailView, UserDeleteView, PasswordResetView,
@ -46,7 +46,7 @@ urlpatterns = [
path('documents/<int:pk>/download/', download_document, name='download_document'),
# download_attachment
path('attachments/<int:pk>/download/', download_attachment, name='download_attachment'),
path('attachments/<int:pk>/download/', download_attachment, name='download_attachment'),
path('user/status/<int:pk>/', change_user_status, name='change_user_status'),

View file

@ -16,6 +16,7 @@ from opportunity.models import Opportunity
from cases.models import Case
from contacts.models import Contact
from accounts.models import Account
from leads.models import Lead
from django.template.loader import render_to_string
@ -42,6 +43,15 @@ class AdminRequiredMixin(AccessMixin):
class HomeView(LoginRequiredMixin, TemplateView):
template_name = "index.html"
def get_context_data(self, **kwargs):
context = super(HomeView, self).get_context_data(**kwargs)
context["accounts"] = Account.objects.filter(status="open")
context["contacts_count"] = Contact.objects.count()
context["leads_count"] = Lead.objects.count()
context["opportunities"] = Opportunity.objects.all()
return context
class ChangePasswordView(LoginRequiredMixin, TemplateView):
template_name = "change_password.html"
@ -88,21 +98,19 @@ class LoginView(TemplateView):
if user.is_active:
login(request, user)
return HttpResponseRedirect('/')
else:
return render(request, "login.html", {
"error": True,
"message": "Your Account is InActive. Please Contact Administrator"
})
else:
return render(request, "login.html", {
"error": True,
"message": "Your Account is not Found. Please Contact Administrator"
"message": "Your Account is InActive. Please Contact Administrator"
})
else:
return render(request, "login.html", {
"error": True,
"message": "Your username and password didn't match. Please try again."
"message": "Your Account is not Found. Please Contact Administrator"
})
return render(request, "login.html", {
"error": True,
"message": "Your username and password didn't match. Please try again."
})
class ForgotPasswordView(TemplateView):
@ -260,7 +268,6 @@ class PasswordResetView(PasswordResetView):
email_template_name = 'registration/password_reset_email.html'
class DocumentCreateView(LoginRequiredMixin, CreateView):
model = Document
form_class = DocumentForm
@ -362,7 +369,7 @@ class DocumentDetailView(LoginRequiredMixin, DetailView):
def get_context_data(self, **kwargs):
context = super(DocumentDetailView, self).get_context_data(**kwargs)
documents = Document.objects.all()
# documents = Document.objects.all()
context.update({
"file_type_code": self.object.file_type()[1],
"doc_obj": self.object,

View file

@ -35,8 +35,8 @@ class Migration(migrations.Migration):
('teams', models.ManyToManyField(to='common.Team')),
],
),
migrations.AlterUniqueTogether(
name='contact',
unique_together={('email',)},
),
# migrations.AlterUniqueTogether(
# name='contact',
# unique_together={('email',)},
# ),
]

View file

@ -2,20 +2,18 @@ import json
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.sites.shortcuts import get_current_site
from django.core.mail import EmailMessage
from django.db.models import Q
from django.http import JsonResponse
from django.shortcuts import get_object_or_404, redirect
from django.template.loader import render_to_string
from django.urls import reverse
from django.views.generic import (
CreateView, UpdateView, DetailView, ListView, TemplateView, View, DeleteView)
CreateView, UpdateView, DetailView, TemplateView, View)
from accounts.models import Account
from common.models import User, Address, Comment, Team, Attachments
from common.models import User, Comment, Team, Attachments
from common.forms import BillingAddressForm
from common.utils import COUNTRIES
from contacts.models import Contact
from contacts.forms import ContactForm, ContactCommentForm, ContactAttachmentForm
from django.urls import reverse
class ContactsListView(LoginRequiredMixin, TemplateView):
@ -77,8 +75,8 @@ class CreateContactView(LoginRequiredMixin, CreateView):
contact_obj.created_by = self.request.user
contact_obj.save()
return self.form_valid(form)
else:
return self.form_invalid(form)
return self.form_invalid(form)
def form_valid(self, form):
contact_obj = form.save(commit=False)
@ -103,11 +101,11 @@ class CreateContactView(LoginRequiredMixin, CreateView):
return JsonResponse({'error': False})
if self.request.POST.get("savenewform"):
return redirect("contacts:add_contact")
elif self.request.POST.get('from_account'):
if self.request.POST.get('from_account'):
from_account = self.request.POST.get('from_account')
return redirect("accounts:view_account", pk=from_account)
else:
return redirect('contacts:list')
return redirect('contacts:list')
def form_invalid(self, form):
address_form = BillingAddressForm(self.request.POST)
@ -190,8 +188,7 @@ class UpdateContactView(LoginRequiredMixin, UpdateView):
contact_obj.address = addres_obj
contact_obj.save()
return self.form_valid(form)
else:
return self.form_invalid(form)
return self.form_invalid(form)
def form_valid(self, form):
assigned_to_ids = self.get_object().assigned_to.all().values_list('id', flat=True)
@ -276,12 +273,11 @@ class RemoveContactView(LoginRequiredMixin, View):
self.object.delete()
if self.request.is_ajax():
return JsonResponse({'error': False})
else:
if request.GET.get('view_account'):
account = request.GET.get('view_account')
return redirect("accounts:view_account", pk=account)
else:
return redirect("contacts:list")
if request.GET.get('view_account'):
account = request.GET.get('view_account')
return redirect("accounts:view_account", pk=account)
return redirect("contacts:list")
class AddCommentView(LoginRequiredMixin, CreateView):
@ -300,11 +296,11 @@ class AddCommentView(LoginRequiredMixin, CreateView):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
else:
data = {'error': "You don't have permission to comment."}
return JsonResponse(data)
return self.form_invalid(form)
data = {'error': "You don't have permission to comment."}
return JsonResponse(data)
def form_valid(self, form):
comment = form.save(commit=False)
@ -330,11 +326,11 @@ class UpdateCommentView(LoginRequiredMixin, View):
form = ContactCommentForm(request.POST, instance=self.comment_obj)
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
else:
data = {'error': "You don't have permission to edit this comment."}
return JsonResponse(data)
return self.form_invalid(form)
data = {'error': "You don't have permission to edit this comment."}
return JsonResponse(data)
def form_valid(self, form):
self.comment_obj.comment = form.cleaned_data.get("comment")
@ -356,9 +352,9 @@ class DeleteCommentView(LoginRequiredMixin, View):
self.object.delete()
data = {"cid": request.POST.get("comment_id")}
return JsonResponse(data)
else:
data = {'error': "You don't have permission to delete this comment."}
return JsonResponse(data)
data = {'error': "You don't have permission to delete this comment."}
return JsonResponse(data)
class GetContactsView(LoginRequiredMixin, TemplateView):
@ -388,11 +384,11 @@ class AddAttachmentsView(LoginRequiredMixin, CreateView):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
else:
data = {'error': "You don't have permission to add attachment."}
return JsonResponse(data)
return self.form_invalid(form)
data = {'error': "You don't have permission to add attachment."}
return JsonResponse(data)
def form_valid(self, form):
attachment = form.save(commit=False)
@ -418,11 +414,13 @@ class DeleteAttachmentsView(LoginRequiredMixin, View):
def post(self, request, *args, **kwargs):
self.object = get_object_or_404(Attachments, id=request.POST.get("attachment_id"))
if (request.user == self.object.created_by or request.user.is_superuser or
request.user.role == 'ADMIN'):
if (
request.user == self.object.created_by or request.user.is_superuser or
request.user.role == 'ADMIN'
):
self.object.delete()
data = {"aid": request.POST.get("attachment_id")}
return JsonResponse(data)
else:
data = {'error': "You don't have permission to delete this attachment."}
return JsonResponse(data)
data = {'error': "You don't have permission to delete this attachment."}
return JsonResponse(data)

View file

@ -7,7 +7,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SECRET_KEY = 'mwx@&97%!$fx_*zgj(2ygi^(s=oh5j(cqb$=+-mkd9scbt!0v0'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DEBUG = False
ALLOWED_HOSTS = ['*']

View file

@ -1,5 +1,4 @@
from django.db import models
from datetime import datetime
# Create your models here.

View file

@ -1,6 +1,6 @@
from django import forms
from leads.models import Lead
from common.models import Address, Comment, Attachments
from common.models import Comment, Attachments
class LeadForm(forms.ModelForm):

View file

@ -20,8 +20,8 @@
<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">
<div class="overview_form_block row marl justify-content-center">
<div class="col-md-9">
<div class="card">
<div class="card-body">
@ -29,7 +29,7 @@
{% if lead_obj %}EDIT{% else %}CREATE{% endif %} LEAD
</div>
<div class="row marl no-gutters">
<div class="col-md-6">
<div class="col-md-4">
<div class="filter_col col-md-12">
<div class="form-group">
<label for="exampleInputEmail1" class="name" >Name{% if lead_form.first_name.field.required %}<span class="error">*</span>{% endif %}</label>
@ -76,6 +76,9 @@
<span class="error">{{ lead_form.email.errors }}</span>
</div>
</div>
</div>
<div class="col-md-4">
<div class="filter_col col-md-12">
<div class="form-group">
<label for="exampleInputEmail1">Website{% if lead_form.website.field.required %}<span class="error">*</span>{% endif %}</label>
@ -90,9 +93,7 @@
<span class="error">{{ lead_form.description.errors }}</span>
</div>
</div>
</div>
<div class="col-md-6">
<div class="filter_col col-md-12">
<div class="filter_col col-md-12">
<div class="form-group">
<label for="exampleInputEmail1">Assigned Users</label>
<select class="assigned_users form-control" name="assigned_to" multiple="multiple">
@ -103,7 +104,7 @@
<span class="error">{{ lead_form.assigned_to.errors }}</span>
</div>
</div>
<br>
<div class="filter_col col-md-12">
<div class="form-group">
<label for="exampleInputEmail1"/>Status{% if lead_form.status.field.required %}<span class="error">*</span>{% endif %}</label>
@ -111,6 +112,9 @@
<span class="error">{{ lead_form.status.errors }}</span>
</div>
</div>
</div>
<div class="col-md-4">
<div class="filter_col col-md-12">
<div class="form-group">
<label for="exampleInputEmail1"/>Source{% if lead_form.source.field.required %}<span class="error">*</span>{% endif %}</label>
@ -154,20 +158,22 @@
</div>
</div>
</div>
<div class="col-md-12">
<div class="row marl buttons_row text-center form_btn_row">
<button class="btn btn-default save" type="submit">Save</button>
{% if not lead_obj %}
<button class="btn btn-success save savenew" type="submit">Save & New</button>
{% endif %}
<a href="{% url 'leads:list' %}" class="btn btn-default clear" id="create_lead_cancel">Cancel</a>
</div>
</div>
</div>
</div>
<br clear="all">
</div>
</div>
<input type="hidden" id="save_new_form" name="savenewform">
</div>
<div class="row marl buttons_row text-center form_btn_row">
<button class="btn btn-default save" type="submit">Save</button>
{% if not lead_obj %}
<button class="btn btn-success save savenew" type="submit">Save & New</button>
{% endif %}
<a href="{% url 'leads:list' %}" class="btn btn-default clear" id="create_lead_cancel">Cancel</a>
</div>
</form>
{% endblock %}
{% block js_block %}

View file

@ -72,7 +72,7 @@
<div class="card-body">
<div class="card-title text-right">
<span class="float-left">Contacts - {% if show_pageitems %} {% show_pageitems %}{% else %} {{ lead_obj|length }}{% endif %}</span>
<span class="float-left">Leads - {% if show_pageitems %} {% show_pageitems %}{% else %} {{ lead_obj|length }}{% endif %}</span>
<span class="filter_toggle">
<a href="#" class="primary_btn"><i class="fas fa-filter"></i></a>
</span>
@ -83,12 +83,12 @@
{% if lead_obj|length > 0 %}
<tr>
<th width="5%">ID</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>
<th width="10%">Name</th>
<th width="10%">Status</th>
<th width="20%">Assigned User</th>
<th width="20%">Tags</th>
<th width="15%">Created On</th>
<th width="10%">Actions</th>
</tr>
{% endif %}
</thead>

View file

@ -19,7 +19,6 @@ from leads.models import Lead
from leads.forms import LeadCommentForm, LeadForm, LeadAttachmentForm
from planner.models import Event, Reminder
from planner.forms import ReminderForm
from django.urls import reverse
class LeadListView(LoginRequiredMixin, TemplateView):
@ -78,8 +77,8 @@ class CreateLeadView(LoginRequiredMixin, CreateView):
address_form = BillingAddressForm(request.POST)
if form.is_valid() and address_form.is_valid():
return self.form_valid(form, address_form)
else:
return self.form_invalid(form, address_form)
return self.form_invalid(form, address_form)
def form_valid(self, form, address_form):
address_object = address_form.save()
@ -88,15 +87,15 @@ class CreateLeadView(LoginRequiredMixin, CreateView):
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)
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')
@ -145,8 +144,7 @@ class CreateLeadView(LoginRequiredMixin, CreateView):
account_object.save()
if self.request.POST.get("savenewform"):
return redirect("leads:add_lead")
else:
return redirect('leads:list')
return redirect('leads:list')
def form_invalid(self, form, address_form):
return self.render_to_response(
@ -251,8 +249,8 @@ class UpdateLeadView(LoginRequiredMixin, UpdateView):
form.fields['account_name'].required = False
if form.is_valid() and address_form.is_valid():
return self.form_valid(form, address_form)
else:
return self.form_invalid(form, address_form)
return self.form_invalid(form, address_form)
def form_valid(self, form, address_form):
assigned_to_ids = self.get_object().assigned_to.all().values_list('id', flat=True)
@ -264,15 +262,15 @@ class UpdateLeadView(LoginRequiredMixin, UpdateView):
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)
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":
@ -329,8 +327,8 @@ class UpdateLeadView(LoginRequiredMixin, UpdateView):
status = self.request.GET.get('status', None)
if status:
return redirect('accounts:list')
else:
return redirect('leads:list')
return redirect('leads:list')
def form_invalid(self, form, address_form):
return self.render_to_response(
@ -406,9 +404,9 @@ class ConvertLeadView(LoginRequiredMixin, View):
email = EmailMessage(mail_subject, message, to=[user.email])
email.send()
return redirect("accounts:list")
else:
return HttpResponseRedirect(
reverse('leads:edit_lead', kwargs={'pk': lead_obj.id}) + '?status=converted')
return HttpResponseRedirect(
reverse('leads:edit_lead', kwargs={'pk': lead_obj.id}) + '?status=converted')
class AddCommentView(LoginRequiredMixin, CreateView):
@ -427,11 +425,11 @@ class AddCommentView(LoginRequiredMixin, CreateView):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
else:
data = {'error': "You don't have permission to comment."}
return JsonResponse(data)
return self.form_invalid(form)
data = {'error': "You don't have permission to comment."}
return JsonResponse(data)
def form_valid(self, form):
comment = form.save(commit=False)
@ -457,11 +455,11 @@ class UpdateCommentView(LoginRequiredMixin, View):
form = LeadCommentForm(request.POST, instance=self.comment_obj)
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
else:
data = {'error': "You don't have permission to edit this comment."}
return JsonResponse(data)
return self.form_invalid(form)
data = {'error': "You don't have permission to edit this comment."}
return JsonResponse(data)
def form_valid(self, form):
self.comment_obj.comment = form.cleaned_data.get("comment")
@ -483,9 +481,9 @@ class DeleteCommentView(LoginRequiredMixin, View):
self.object.delete()
data = {"cid": request.POST.get("comment_id")}
return JsonResponse(data)
else:
data = {'error': "You don't have permission to delete this comment."}
return JsonResponse(data)
data = {'error': "You don't have permission to delete this comment."}
return JsonResponse(data)
class GetLeadsView(LoginRequiredMixin, ListView):
@ -515,11 +513,10 @@ class AddAttachmentsView(LoginRequiredMixin, CreateView):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
else:
data = {'error': "You don't have permission to add attachment."}
return JsonResponse(data)
return self.form_invalid(form)
data = {'error': "You don't have permission to add attachment."}
return JsonResponse(data)
def form_valid(self, form):
attachment = form.save(commit=False)
@ -545,11 +542,13 @@ class DeleteAttachmentsView(LoginRequiredMixin, View):
def post(self, request, *args, **kwargs):
self.object = get_object_or_404(Attachments, id=request.POST.get("attachment_id"))
if (request.user == self.object.created_by or request.user.is_superuser or
request.user.role == 'ADMIN'):
if (
request.user == self.object.created_by or request.user.is_superuser or
request.user.role == 'ADMIN'
):
self.object.delete()
data = {"aid": request.POST.get("attachment_id")}
return JsonResponse(data)
else:
data = {'error': "You don't have permission to delete this attachment."}
return JsonResponse(data)
data = {'error': "You don't have permission to delete this attachment."}
return JsonResponse(data)

View file

@ -12,7 +12,8 @@ if __name__ == "__main__":
# issue is really that Django is missing to avoid masking other
# exceptions on Python 2.
try:
import django
pass
except ImportError:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "

View file

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

View file

@ -2,7 +2,7 @@ from django.db import models
from django.utils.translation import pgettext_lazy
from django.utils.translation import ugettext_lazy as _
from accounts.models import Account
from accounts.models import Account, Tags
from contacts.models import Contact
from common.models import User, Team
from common.utils import STAGES, SOURCES, CURRENCY_CODES
@ -27,6 +27,7 @@ class Opportunity(models.Model):
created_by = models.ForeignKey(User, related_name='opportunity_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)
class Meta:
ordering = ['-created_on']

View file

@ -12,6 +12,12 @@
</nav>
{% 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 class= "form_user" method="POST" action="" novalidate>
<div class="overview_form_block row marl justify-content-center">
<div class="col-md-9">
@ -39,21 +45,15 @@
<div class="filter_col col-md-12">
<div class="form-group">
<label for="exampleInputEmail1">Amount</label>
<div class="input-group" style="width:100%;">
<div class="input-group-btn left-dropdown" style="width:auto;">
{{request.POST.assigned_to}}
<select class="assigned_users form-control" name="assigned_to" multiple="multiple">
{% for user in users %}
<option value="{{user.id}}" {% if user in account_obj.assigned_to.all or user.id in assignedto_list %} selected="" {% endif %}>{{user.email}}</option>
{% endfor %}
</select>
{{ account_form.assigned_to.errors }}
{{ opportunity_form.currency }}
<span class="error">{{opportunity_form.currency.errors}}</span>
</div>
{{ opportunity_form.amount }}
{{ opportunity_form.amount }}
<span class="error">{{opportunity_form.amount.errors}}</span>
</div>
</div>
</div>
<div class="filter_col col-md-12">
<div class="form-group">
<label for="exampleInputEmail1">Currency</label>
{{ opportunity_form.currency }}
<span class="error">{{opportunity_form.currency.errors}}</span>
</div>
</div>
<div class="filter_col col-md-12">
@ -97,10 +97,6 @@
<span class="error">{{opportunity_form.contacts.errors}}</span>
</div>
</div>
</div>
<div class="col-md-4">
<div class="filter_col col-md-12">
<div class="form-group">
<label for="exampleInputEmail1">Close Date{% if opportunity_form.closed_on.field.required %}<span class="error">*</span>{% endif %}</label>
@ -113,6 +109,15 @@
<span class="error">{{opportunity_form.closed_on.errors}}</span>
</div>
</div>
</div>
<div class="col-md-4">
<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 opportunity_obj.tags.all %}{{t.name}}, {% endfor %}" class="tags"/>
</div>
</div>
</div>
<div class="form-group col-md-12">
<label for="exampleInputEmail1" >Description{% if opportunity_form.description.field.required %}<span class="error">*</span>{% endif %}</label>
{{ opportunity_form.description }}
@ -142,6 +147,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">
$(function () {
var date = new Date();
@ -290,6 +297,45 @@
});
}
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

@ -109,6 +109,18 @@
</div>
{% endif %}
</div>
{% if opportunity_record.tags.all %}
<div class="filter_col col-md-12">
<div class="form-group">
<label class="acc_field_label" for="id_tags" data-name="name">Tags</label>
<div class="account_field" id="account_tags" data-name="name">
{% for tag in opportunity_record.tags.all %}
<span class="text-left" id="list_tag">{{ tag.name }}</span>
{% endfor %}
</div>
</div>
</div>
{% endif %}
</div>
<div class="col-md-12">
<div class="created_information">

View file

@ -2,7 +2,7 @@ from django.urls import path
from opportunity.views import (
OpportunityListView, CreateOpportunityView, OpportunityDetailView, UpdateOpportunityView,
DeleteOpportunityView, GetContactView, GetOpportunitiesView, AddCommentView,
UpdateCommentView, DeleteCommentView,AddAttachmentsView,DeleteAttachmentsView)
UpdateCommentView, DeleteCommentView,AddAttachmentsView)
app_name = 'opportunity'

View file

@ -6,7 +6,7 @@ from django.http import JsonResponse
from django.shortcuts import get_object_or_404, redirect
from django.template.loader import render_to_string
from django.views.generic import CreateView, UpdateView, DetailView, ListView, TemplateView, View
from accounts.models import Account
from accounts.models import Account, Tags
from common.models import User, Comment, Team, Attachments
from common.utils import STAGES, SOURCES, CURRENCY_CODES
from contacts.models import Contact
@ -73,8 +73,7 @@ class CreateOpportunityView(LoginRequiredMixin, CreateView):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
return self.form_invalid(form)
def form_valid(self, form):
opportunity_obj = form.save(commit=False)
@ -101,6 +100,16 @@ class CreateOpportunityView(LoginRequiredMixin, CreateView):
opportunity_obj.teams.add(*self.request.POST.getlist('teams'))
if self.request.POST.getlist('contacts', []):
opportunity_obj.contacts.add(*self.request.POST.getlist('contacts'))
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())
opportunity_obj.tags.add(tag)
if self.request.is_ajax():
return JsonResponse({'error': False})
if self.request.POST.get("savenewform"):
@ -108,8 +117,7 @@ class CreateOpportunityView(LoginRequiredMixin, CreateView):
if self.request.POST.get('from_account'):
from_account = self.request.POST.get('from_account')
return redirect("accounts:view_account", pk=from_account)
else:
return redirect('opportunities:list')
return redirect('opportunities:list')
def form_invalid(self, form):
if self.request.is_ajax():
@ -185,8 +193,7 @@ class UpdateOpportunityView(LoginRequiredMixin, UpdateView):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
return self.form_invalid(form)
def form_valid(self, form):
assigned_to_ids = self.get_object().assigned_to.all().values_list('id', flat=True)
@ -221,7 +228,17 @@ class UpdateOpportunityView(LoginRequiredMixin, UpdateView):
opportunity_obj.teams.add(*self.request.POST.getlist('teams'))
if self.request.POST.getlist('contacts', []):
opportunity_obj.contacts.add(*self.request.POST.getlist('contacts'))
opportunity_obj.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())
opportunity_obj.tags.add(tag)
if self.request.POST.get('from_account'):
from_account = self.request.POST.get('from_account')
return redirect("accounts:view_account", pk=from_account)
@ -265,12 +282,12 @@ class DeleteOpportunityView(LoginRequiredMixin, View):
self.object.delete()
if request.is_ajax():
return JsonResponse({'error': False})
else:
if request.GET.get('view_account'):
account = request.GET.get('view_account')
return redirect("accounts:view_account", pk=account)
else:
return redirect("opportunities:list")
if request.GET.get('view_account'):
account = request.GET.get('view_account')
return redirect("accounts:view_account", pk=account)
return redirect("opportunities:list")
class GetContactView(LoginRequiredMixin, View):
@ -302,11 +319,10 @@ class AddCommentView(LoginRequiredMixin, CreateView):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
else:
data = {'error': "You don't have permission to comment."}
return JsonResponse(data)
return self.form_invalid(form)
data = {'error': "You don't have permission to comment."}
return JsonResponse(data)
def form_valid(self, form):
comment = form.save(commit=False)
@ -332,11 +348,10 @@ class UpdateCommentView(LoginRequiredMixin, View):
form = OpportunityCommentForm(request.POST, instance=self.comment_obj)
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
else:
data = {'error': "You don't have permission to edit this comment."}
return JsonResponse(data)
return self.form_invalid(form)
data = {'error': "You don't have permission to edit this comment."}
return JsonResponse(data)
def form_valid(self, form):
self.comment_obj.comment = form.cleaned_data.get("comment")
@ -358,9 +373,9 @@ class DeleteCommentView(LoginRequiredMixin, View):
self.object.delete()
data = {"cid": request.POST.get("comment_id")}
return JsonResponse(data)
else:
data = {'error': "You don't have permission to delete this comment."}
return JsonResponse(data)
data = {'error': "You don't have permission to delete this comment."}
return JsonResponse(data)
class GetOpportunitiesView(LoginRequiredMixin, ListView):
@ -390,11 +405,10 @@ class AddAttachmentsView(LoginRequiredMixin, CreateView):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
else:
data = {'error': "You don't have permission to add attachment."}
return JsonResponse(data)
return self.form_invalid(form)
data = {'error': "You don't have permission to add attachment."}
return JsonResponse(data)
def form_valid(self, form):
attachment = form.save(commit=False)
@ -420,11 +434,10 @@ class DeleteAttachmentsView(LoginRequiredMixin, View):
def post(self, request, *args, **kwargs):
self.object = get_object_or_404(Attachments, id=request.POST.get("attachment_id"))
if (request.user == self.object.created_by or request.user.is_superuser or
request.user.role == 'ADMIN'):
if (request.user == self.object.created_by or request.user.is_superuser or request.user.role == 'ADMIN'):
self.object.delete()
data = {"aid": request.POST.get("attachment_id")}
return JsonResponse(data)
else:
data = {'error': "You don't have permission to delete this attachment."}
return JsonResponse(data)
data = {'error': "You don't have permission to delete this attachment."}
return JsonResponse(data)

View file

@ -3,6 +3,5 @@ from django.contrib import admin
from planner.models import Event, Reminder
# Register your models here.
admin.site.register(Event)
admin.site.register(Reminder)
admin.site.register(Reminder)

View file

@ -72,6 +72,7 @@ a{
}
.errorlist li{
color: red;
font-size: 0.83rem;
}
label {
font-size: 14px;
@ -864,8 +865,9 @@ padding:0px !important;
}
#list_tag{
background: #e5e5e5;
color: #555;
color: #fff;
border: none;
background: #333;
font-weight: 500;
padding: 1px 5px;
margin-right: 5px;
@ -873,7 +875,21 @@ padding:0px !important;
display: inline-block;
margin-bottom: 5px;
border-radius: 2px;
border: 1px solid #bbb;
&.color1{
background: darken($dark_sky, 5%);
}
&.red{
background: darken($color_cerise_red_approx, 5%);
}
&.green{
background: darken($green, 5%);
}
&.color2{
background: darken($dark_yellow, 10%);
}
&.color3{
background: darken($color_apricot_peach_approx, 40%);
}
}
.nav-tabs{
li{
@ -973,20 +989,24 @@ pre{
.item{
background: #fff;
border-radius: 0;
border: 1px solid #dedede;
padding:0;
border: none;
text-align: center;
.title{
background: #dedede;
line-height: 2.5rem;
font-weight: 600;
font-size: 0.85rem;
color: #fff;
text-transform: uppercase;
a{
color: #fff;
}
}
.count{
font-size: 2rem;
font-weight: 600;
padding: 0.5rem 0;
color: #fff;
}
.more{
font-size: 0.85rem;
@ -1013,6 +1033,18 @@ pre{
}
}
}
&.sky_blue{
background: darken($dark_sky, 10%);
}
&.red{
background: darken($color_cerise_red_approx, 10%);
}
&.green{
background: darken($green, 5%);
}
&.yellow{
background: darken($dark_yellow, 10%);
}
}
}
/* open_sections */
@ -1021,6 +1053,21 @@ pre{
.table_container_row{
.table{
margin-bottom: 0;
tbody{
tr{
td{
a{
color: #333;
font-weight: 600;
}
}
}
}
}
}
}
.errorlist{
li{
font-size: 0.83rem;
}
}

View file

@ -16,6 +16,7 @@ $green:#41B871;
$dark_sky:#099CBE;
$dark_yellow:#FEA124;
$inner_page_bg:#CDCDCD;
$green: #5cca64;

View file

@ -31,6 +31,7 @@
{% if request.user.is_authenticated %}
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item"><a class="nav-link" id="dashboard" href="{% url 'common:home' %}">Dashboard</a></li>
{% if request.user.role == "ADMIN" or request.user.is_superuser %}
<li class="nav-item"><a class="nav-link" id="users" href="{% url 'common:users_list' %}">Users</a></li>
{% endif %}
@ -94,7 +95,12 @@
<script type="text/javascript">
$(document).ready(function(){
word = window.location.pathname.split('/')[1]
$('#' + word).addClass('active')
if(word == ""){
$("#dashboard").addClass('active')
}
else{
$('#' + word).addClass('active')
}
})
</script>
</body>

View file

@ -1,37 +1,46 @@
{% extends 'base.html' %}
{% load staticfiles %}
{% block content %}
{% load common_tags %}
<!-- <a href="{% url "common:logout" %}"><button class="btn btn-primary" type="button">Logout</button></a> -->
<div class="row marl justify-content-center">
<div class="col-md-9">
<!-- count_blocks_row starts here -->
<div class="row count_blocks_row">
<div class="col-md-3">
<div class="item">
<div class="title">Accounts</div>
<div class="count">100</div>
<div class="more"><a href="#">Go Live</a></div>
<div class="item sky_blue">
<a href="{% url 'accounts:list'%}">
<div class="title">Accounts</div>
<div class="count">{{accounts|length}}</div>
<!-- <div class="more"><a href="#">Go Live</a></div> -->
</a>
</div>
</div>
<div class="col-md-3">
<div class="item">
<div class="title">Contacts</div>
<div class="count">3520</div>
<div class="more "><a href="#">Go Live</a></div>
<div class="item green">
<a href="{% url 'contacts:list' %}">
<div class="title">Contacts</div>
<div class="count">{{contacts_count}}</div>
</a>
<!-- <div class="more"><a href="#">Go Live</a></div> -->
</div>
</div>
<div class="col-md-3">
<div class="item">
<div class="title">Leads</div>
<div class="count">47</div>
<div class="more "><a href="#">Go Live</a></div>
<div class="item red">
<a href="{% url 'leads:list' %}">
<div class="title">Leads</div>
<div class="count">{{leads_count}}</div>
<!-- <div class="more"><a href="#">Go Live</a></div> -->
</a>
</div>
</div>
<div class="col-md-3">
<div class="item">
<div class="title">Opportunities</div>
<div class="count">80</div>
<div class="more "><a href="#">Go Live</a></div>
<div class="item yellow">
<a href="{% url 'opportunity:list' %}">
<div class="title">Opportunities</div>
<div class="count">{{opportunities|length}}</div>
<!-- <div class="more"><a href="#">Go Live</a></div> -->
</a>
</div>
</div>
</div>
@ -52,48 +61,21 @@
</tr>
</thead>
<tbody>
{% for account in accounts|slice:"15" %}
<tr>
<td><a href="/contacts/1/view/">santharao</a></td>
<td><a href="{% url 'accounts:view_account' account.id %}">{{account.name}}</a></td>
<td style="display: block;">
<span class="text-left" id="list_tag">design</span>
<span class="text-left" id="list_tag">device</span>
</td>
</tr>
<tr>
<td><a href="/contacts/1/view/">santharao</a></td>
<td style="display: block;">
<span class="text-left" id="list_tag">design</span>
<span class="text-left" id="list_tag">device</span>
</td>
</tr>
<tr>
<td><a href="/contacts/1/view/">santharao</a></td>
<td style="display: block;">
<span class="text-left" id="list_tag">design</span>
<span class="text-left" id="list_tag">device</span>
</td>
</tr>
<tr>
<td><a href="/contacts/1/view/">santharao</a></td>
<td style="display: block;">
<span class="text-left" id="list_tag">design</span>
<span class="text-left" id="list_tag">device</span>
</td>
</tr>
<tr>
<td><a href="/contacts/1/view/">santharao</a></td>
<td style="display: block;">
<span class="text-left" id="list_tag">design</span>
<span class="text-left" id="list_tag">device</span>
</td>
</tr>
<tr>
<td><a href="/contacts/1/view/">santharao</a></td>
<td style="display: block;">
<span class="text-left" id="list_tag">design</span>
<span class="text-left" id="list_tag">device</span>
{% for tag in account.tags.all|slice:'3' %}
<span class="text-left color{{forloop.counter}}" id="list_tag">{{tag.name}}</span>
{% empty %}
<span class="text-left">No Tags</span>
{% endfor %}
{% if account.tags.all|length > 3 %}
<span class="text-left" id="list_tag">{{account.tags.all|length|subtract:'3'}}<span>+</span></span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
@ -115,48 +97,21 @@
</tr>
</thead>
<tbody>
{% for opportunity in opportunities|slice:"15" %}
<tr>
<td><a href="/contacts/1/view/">Opportunity1</a></td>
<td><a href="{% url 'opportunity:opp_view' opportunity.id %}">{{opportunity.name}}</a></td>
<td style="display: block;">
<span class="text-left" id="list_tag">test</span>
<span class="text-left" id="list_tag">test2</span>
</td>
</tr>
<tr>
<td><a href="/contacts/1/view/">Opportunity2</a></td>
<td style="display: block;">
<span class="text-left" id="list_tag">test2</span>
<span class="text-left" id="list_tag">device</span>
</td>
</tr>
<tr>
<td><a href="/contacts/1/view/">Opportunity5</a></td>
<td style="display: block;">
<span class="text-left" id="list_tag">tst3</span>
<span class="text-left" id="list_tag">device</span>
</td>
</tr>
<tr>
<td><a href="/contacts/1/view/">Opportunity3</a></td>
<td style="display: block;">
<span class="text-left" id="list_tag">bug</span>
<span class="text-left" id="list_tag">bugs</span>
</td>
</tr>
<tr>
<td><a href="/contacts/1/view/">Opportunity5</a></td>
<td style="display: block;">
<span class="text-left" id="list_tag">edit</span>
<span class="text-left" id="list_tag">delete</span>
</td>
</tr>
<tr>
<td><a href="/contacts/1/view/">Opportunity5</a></td>
<td style="display: block;">
<span class="text-left" id="list_tag">webdesign</span>
<span class="text-left" id="list_tag">testing</span>
{% for tag in opportunity.tags.all|slice:'3' %}
<span class="text-left color{{forloop.counter}}" id="list_tag">{{tag.name}}</span>
{% empty %}
<span class="text-left">No Tags</span>
{% endfor %}
{% if opportunity.tags.all|length > 3 %}
{{opportunity.tags.all|length|subtract:'3'}}<span>+</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>