Skip to content

Commit c6cecb4

Browse files
authored
added django storages, loading local or aws storages based on env variable, removed reset password option for loggedin user, fixed issue of account edit in account list, removed address text in leads create page, properly aligining attachments, fixed issue of unable to see assigned contacts in edit account page (#207)
1 parent 5076b09 commit c6cecb4

File tree

98 files changed

+4177
-707
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+4177
-707
lines changed

.gitlab-ci.yml

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
Python 3.5.2:
2+
script:
3+
- export PY_EXE=python3.5.2
4+
- virtualenv -p python3 env
5+
- source env/bin/activate
6+
- pip install --no-cache-dir -r requirements.txt
7+
- python manage.py test --noinput
8+
- coverage run --source=accounts,cases,common,contacts,emails,leads,opportunity,planner manage.py test --noinput
9+
- coverage report -m
10+
except:
11+
- tags
12+
13+
deploy_mp:
14+
stage: deploy
15+
environment:
16+
name: live
17+
script:
18+
- sudo /bin/rm -rf /home/dj_crm/dj_crm/; cp -r . /home/dj_crm/dj_crm
19+
- source /home/dj_crm/env/bin/activate
20+
- pip install -r /home/dj_crm/dj_crm/requirements.txt
21+
- python /home/dj_crm/dj_crm/manage.py migrate --noinput
22+
- sudo /etc/init.d/uwsgi restart
23+
only:
24+
- master
25+
tags:
26+
- djcrm_micropyramid
27+
28+
deploy_live:
29+
stage: deploy
30+
environment:
31+
name: live
32+
script:
33+
- sudo /bin/rm -rf /home/dj_crm/dj_crm/; cp -r . /home/dj_crm/dj_crm
34+
- source /home/dj_crm/env/bin/activate
35+
- pip install -r /home/dj_crm/dj_crm/requirements.txt
36+
- python /home/dj_crm/dj_crm/manage.py migrate --noinput
37+
- sudo /etc/init.d/uwsgi restart
38+
only:
39+
- master
40+
tags:
41+
- github-crm

README.rst

+13-3
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,26 @@ This project contains the following modules.
6565

6666
Try
6767
===
68+
6869
Demo Available `here`_.
6970

7071
Demo credentials for Django CRM:
7172

7273
* **Email:** admin@micropyramid.com
7374
* **Password:** admin
7475

75-
Contribution
76-
============
77-
We need contributions in UI development and documentation.
76+
77+
Community
78+
=========
79+
80+
Get help or stay up to date.
81+
82+
- [Contribute on Issues](https://github.com/MicroPyramid/Django-CRM/issues)
83+
- Follow [@micropyramid](https://twitter.com/micropyramid) on Twitter
84+
- Ask questions on [Stack Overflow](https://stackoverflow.com/questions/tagged/django-crm)
85+
- Chat with community [Gitter](https://gitter.im/MicroPyramid/Django-CRM)
86+
- For customisations, email django-crm@micropyramid.com
87+
7888

7989
Feature requests and bug reports
8090
================================

accounts/templates/accounts.html

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{% extends 'base.html' %}
1+
{% extends 'sales/base.html' %}
22
{% load staticfiles %}
33
{% load paginate %}
44
{% block extralinks %}
@@ -66,10 +66,10 @@
6666
<div class="col-md-12">
6767
<ul class="nav nav-tabs" id="myTab" role="tablist">
6868
<li class="nav-item">
69-
<a class="nav-link active" id="open-tab" data-toggle="tab" href="#open" role="tab" aria-controls="open" aria-selected="true">Open</a>
69+
<a class="nav-link active" id="open-tab" data-toggle="tab" href="#open" role="tab" aria-controls="open" aria-selected="true">Active ({{open_accounts|length}})</a>
7070
</li>
7171
<li class="nav-item">
72-
<a class="nav-link" id="close-tab" data-toggle="tab" href="#close" role="tab" aria-controls="close" aria-selected="false">Closed</a>
72+
<a class="nav-link" id="close-tab" data-toggle="tab" href="#close" role="tab" aria-controls="close" aria-selected="false">Closed ({{close_accounts|length}})</a>
7373
</li>
7474
</ul>
7575
<div class="tab-content" id="myTabContent">
@@ -244,6 +244,13 @@ <h6 class="text-center">No Closed Acccount Records Found</h6>
244244
$(".reset").click(function(e){
245245
window.location = "{% url 'accounts:list'%}"
246246
});
247+
248+
249+
search = "{{search}}"
250+
251+
if (search == 'True'){
252+
$(".list_filter_row").show();
253+
}
247254

248255
$(document).ready(function(){
249256
$(".filter_toggle").click(function(){

accounts/templates/create_account.html

+28-9
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
{% extends 'base.html' %}
1+
{% extends 'sales/base.html' %}
22
{% load staticfiles %}
33
{% block breadcrumb %}
44
{% block extralinks %}
55
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
6+
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-tagsinput/1.3.6/jquery.tagsinput.min.css" rel="stylesheet">
7+
<link rel="stylesheet" type="text/css" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/themes/start/jquery-ui.css" />
68
{% endblock %}
79
<nav aria-label="breadcrumb">
810
<ol class="breadcrumb">
@@ -12,12 +14,7 @@
1214
</nav>
1315
{% endblock %}
1416
{% block content %}
15-
<head>
16-
<link rel="stylesheet" type="text/css" href="//xoxco.com/projects/code/tagsinput/jquery.tagsinput.css" />
17-
<script type="text/javascript" src="//xoxco.com/projects/code/tagsinput/jquery.tagsinput.js"></script>
18-
<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js'></script>
19-
<link rel="stylesheet" type="text/css" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/themes/start/jquery-ui.css" />
20-
</head>
17+
{% if contact_count and lead_count %}
2118
<form id="formid" action='' method="POST" novalidate>
2219
<div class="overview_form_block row marl justify-content-center">
2320
<div class="col-md-9">
@@ -121,6 +118,17 @@ <h6 style="color:white;">Copy Address</h6>
121118
</div>
122119
</div>
123120
<div class="col-md-4">
121+
<div class="filter_col col-12">
122+
<div class="form-group">
123+
<label for="exampleInputEmail1">Assigned Users</label>
124+
<select class="assigned_users form-control" name="assigned_to" multiple="multiple">
125+
{% for user in users %}
126+
<option value="{{user.id}}" {% if user in account_obj.assigned_to.all or user.id in assignedto_list %} selected="" {% endif %}>{{user.email}}</option>
127+
{% endfor %}
128+
</select>
129+
{{ account_form.assigned_to.errors }}
130+
</div>
131+
</div>
124132
<div class="filter_col col-12">
125133
<div class="form-group">
126134
<label for="id_sattus">Status{% if account_form.status.field.required %}<span class="error">*</span>{% endif %}</label>
@@ -165,12 +173,23 @@ <h6 style="color:white;">Copy Address</h6>
165173
</div>
166174
<!-- overview ends here -->
167175
</form>
176+
{% else %}
177+
<div class="justify-content-center text-center">
178+
<h3 class="mt-5">create a contacts and leads for creating an account</h3>
179+
</div>
180+
{% endif %}
168181
{% endblock %}
169-
{% block js_block %}
170182
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/js/select2.min.js"></script>
171-
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-tagsinput/1.3.6/jquery.tagsinput.min.css" rel="stylesheet">
183+
{% block js_block %}
184+
<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js'></script>
172185
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-tagsinput/1.3.6/jquery.tagsinput.min.js"></script>
173186
<script type="text/javascript">
187+
188+
$(document).ready(function() {
189+
$('.assigned_users').select2();
190+
});
191+
192+
174193
$("#copy_billing_btn").click(function(){
175194
var address_line = $("#id_address_line").val();
176195
var street = $("#id_street").val();

accounts/templates/error_template.html

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
<div class="main_container">
1010
<!-- heading_create starts here -->
1111

12-
create contacts and leads
12+
<div class="justify-content-center text-center">
13+
<h3 class="mt-5">create a contacts and leads to continue creating an account</h3>
14+
</div>
1315
<!-- filter_row ends here -->
1416
<!-- accounts list start -->
1517
<!-- accounts list end -->

accounts/templates/view_account.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{% extends 'base.html' %}
1+
{% extends 'sales/base.html' %}
22
{% load staticfiles %}
33
{% block breadcrumb %}
44
<!-- breadcrumb starts here -->

accounts/urls.py

+13-13
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
from django.urls import path
22
from accounts.views import (
3-
AccountsListView, CreateAccountView, AccountDetailView, AccountUpdateView,
4-
AccountDeleteView, AddCommentView, UpdateCommentView, DeleteCommentView,
5-
AddAttachmentView, DeleteAttachmentsView
3+
AccountsListView, CreateAccountView, AccountDetailView, AccountUpdateView,
4+
AccountDeleteView, AddCommentView, UpdateCommentView, DeleteCommentView,
5+
AddAttachmentView, DeleteAttachmentsView
66
)
77

88
app_name = 'accounts'
99

1010
urlpatterns = [
11-
path('list/', AccountsListView.as_view(), name='list'),
12-
path('create/', CreateAccountView.as_view(), name='new_account'),
13-
path('<int:pk>/view/', AccountDetailView.as_view(), name="view_account"),
14-
path('<int:pk>/edit/', AccountUpdateView.as_view(), name="edit_account"),
15-
path('<int:pk>/delete/', AccountDeleteView.as_view(), name="remove_account"),
16-
path('comment/add/', AddCommentView.as_view(), name="add_comment"),
17-
path('comment/edit/', UpdateCommentView.as_view(), name="edit_comment"),
18-
path('comment/remove/', DeleteCommentView.as_view(), name="remove_comment"),
11+
path('list/', AccountsListView.as_view(), name='list'),
12+
path('create/', CreateAccountView.as_view(), name='new_account'),
13+
path('<int:pk>/view/', AccountDetailView.as_view(), name="view_account"),
14+
path('<int:pk>/edit/', AccountUpdateView.as_view(), name="edit_account"),
15+
path('<int:pk>/delete/', AccountDeleteView.as_view(), name="remove_account"),
16+
path('comment/add/', AddCommentView.as_view(), name="add_comment"),
17+
path('comment/edit/', UpdateCommentView.as_view(), name="edit_comment"),
18+
path('comment/remove/', DeleteCommentView.as_view(), name="remove_comment"),
1919

20-
path('attachment/add/', AddAttachmentView.as_view(), name="add_attachment"),
21-
path('attachment/remove/', DeleteAttachmentsView.as_view(), name="remove_attachment"),
20+
path('attachment/add/', AddAttachmentView.as_view(), name="add_attachment"),
21+
path('attachment/remove/', DeleteAttachmentsView.as_view(), name="remove_attachment"),
2222
]

accounts/views.py

+23-7
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from django.contrib.sites.shortcuts import get_current_site
44
from django.core.mail import EmailMessage
55
from django.http import JsonResponse
6-
from django.shortcuts import get_object_or_404, redirect
6+
from django.shortcuts import get_object_or_404, redirect, render
77
from django.template.loader import render_to_string
88
from django.views.generic import (
99
CreateView, UpdateView, DetailView, TemplateView, View, DeleteView)
@@ -49,7 +49,16 @@ def get_context_data(self, **kwargs):
4949
context['close_accounts'] = close_accounts
5050
context["industries"] = INDCHOICES
5151
context["per_page"] = self.request.POST.get('per_page')
52-
context['tags'] = Tags.objects.all()
52+
context["tag"] = Tags.objects.all()
53+
54+
search = False
55+
if (
56+
self.request.POST.get('name') or self.request.POST.get('city') or
57+
self.request.POST.get('industry') or self.request.POST.get('tag')
58+
):
59+
search = True
60+
61+
context["search"] = search
5362

5463
tab_status = 'Open'
5564
if self.request.POST.get('tab_status'):
@@ -73,14 +82,11 @@ class CreateAccountView(LoginRequiredMixin, CreateView):
7382

7483
def dispatch(self, request, *args, **kwargs):
7584
self.users = User.objects.filter(is_active=True).order_by('email')
76-
# if Contact.objects.count() == 0:
77-
# return JsonResponse({'message':'create Contact'})
78-
# if Lead.objects.count() == 0:
79-
# return JsonResponse({'message':'create Lead'})
8085
return super(CreateAccountView, self).dispatch(request, *args, **kwargs)
8186

8287
def get_form_kwargs(self):
8388
kwargs = super(CreateAccountView, self).get_form_kwargs()
89+
kwargs.update({"account": True})
8490
return kwargs
8591

8692
def post(self, request, *args, **kwargs):
@@ -107,13 +113,16 @@ def form_valid(self, form):
107113
else:
108114
tag = Tags.objects.create(name=t.lower())
109115
account_object.tags.add(tag)
116+
if self.request.POST.getlist('contacts', []):
117+
account_object.contacts.add(*self.request.POST.getlist('contacts'))
110118
if self.request.FILES.get('account_attachment'):
111119
attachment = Attachments()
112120
attachment.created_by = self.request.user
113121
attachment.file_name = self.request.FILES.get('account_attachment').name
114122
attachment.account = account_object
115123
attachment.attachment = self.request.FILES.get('account_attachment')
116124
attachment.save()
125+
117126
if self.request.POST.get("savenewform"):
118127
return redirect("accounts:new_account")
119128

@@ -130,6 +139,8 @@ def get_context_data(self, **kwargs):
130139
context["users"] = self.users
131140
context["industries"] = INDCHOICES
132141
context["countries"] = COUNTRIES
142+
context["contact_count"] = Contact.objects.count()
143+
context["lead_count"] = Lead.objects.count()
133144
return context
134145

135146

@@ -179,6 +190,7 @@ def dispatch(self, request, *args, **kwargs):
179190

180191
def get_form_kwargs(self):
181192
kwargs = super(AccountUpdateView, self).get_form_kwargs()
193+
kwargs.update({"account": True})
182194
return kwargs
183195

184196
def post(self, request, *args, **kwargs):
@@ -207,6 +219,9 @@ def form_valid(self, form):
207219
else:
208220
tag = Tags.objects.create(name=t.lower())
209221
account_object.tags.add(tag)
222+
if self.request.POST.getlist('contacts', []):
223+
account_object.contacts.clear()
224+
account_object.contacts.add(*self.request.POST.getlist('contacts'))
210225
if self.request.FILES.get('account_attachment'):
211226
attachment = Attachments()
212227
attachment.created_by = self.request.user
@@ -228,7 +243,8 @@ def get_context_data(self, **kwargs):
228243
context["users"] = self.users
229244
context["industries"] = INDCHOICES
230245
context["countries"] = COUNTRIES
231-
246+
context["contact_count"] = Contact.objects.count()
247+
context["lead_count"] = Lead.objects.count()
232248
return context
233249

234250

cases/templates/cases.html

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{% extends 'base.html' %}
1+
{% extends 'sales/base.html' %}
22
{% load staticfiles %}
33
{% load paginate %}
44
{% block content %}
@@ -163,8 +163,14 @@ <h6 class="text-center">No Cases Records Found</h6>
163163
$(".filter_toggle").click(function(){
164164
$(".list_filter_row").toggle();
165165
});
166-
});
167-
166+
});
167+
168+
search = "{{search}}"
169+
170+
if (search == 'True'){
171+
$(".list_filter_row").show();
172+
}
173+
168174
$('.remove_case').click(function(e){
169175
e.preventDefault()
170176
url = $(this).attr('href')

cases/templates/create_cases.html

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{% extends 'base.html' %}
1+
{% extends 'sales/base.html' %}
22
{% load staticfiles %}
33
{% block breadcrumb %}
44
{% block extralinks %}
@@ -109,6 +109,7 @@
109109
<div class="form-group">
110110
<label for="id_contacts">Contacts{% if case_form.contacts.field.required %}<span class="error">*</span>{% endif %}</label>
111111
{{ case_form.contacts }}
112+
<span class="error">{{case_form.contacts.errors}}</span>
112113
</div>
113114
</div>
114115
<div class="filter_col col-md-12">
@@ -160,6 +161,7 @@
160161
});
161162
$(document).ready(function() {
162163
$('.assigned_users').select2();
164+
$("#id_contacts").select2();
163165
});
164166

165167
$('#id_account').change(function(){

cases/templates/show_case.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{% extends 'base.html' %}
1+
{% extends 'sales/base.html' %}
22
{% load staticfiles %}
33
{% block content %}
44
<div class="main_container" id="maincontainer" {% if edit2%}style="display:none"{% endif %}>

cases/templates/view_case.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{% extends 'base.html' %}
1+
{% extends 'sales/base.html' %}
22
{% load staticfiles %}
33
{% block content %}
44
<nav aria-label="breadcrumb">

cases/views.py

+10
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ def get_context_data(self, **kwargs):
4444
context["acc"] = int(self.request.POST.get("account")) if self.request.POST.get("account") else None
4545
context["case_priority"] = PRIORITY_CHOICE
4646
context["case_status"] = STATUS_CHOICE
47+
48+
49+
search = False
50+
if (
51+
self.request.POST.get('name') or self.request.POST.get('account') or
52+
self.request.POST.get('status') or self.request.POST.get('priority')
53+
):
54+
search = True
55+
56+
context["search"] = search
4757
return context
4858

4959
def get(self, request, *args, **kwargs):

0 commit comments

Comments
 (0)