aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFilipp Lepalaan <filipp@mac.com>2015-10-08 10:48:36 +0300
committerFilipp Lepalaan <filipp@mac.com>2015-10-08 10:48:36 +0300
commit2a7251afa0438b1472c66932a4c22d378ae15c28 (patch)
treece9752d1f44369bb5f2b372982e953911303c056
parent88e291a6ed830f11671f04893031eec2291a6703 (diff)
downloadServo-2a7251afa0438b1472c66932a4c22d378ae15c28.tar.gz
Servo-2a7251afa0438b1472c66932a4c22d378ae15c28.tar.bz2
Servo-2a7251afa0438b1472c66932a4c22d378ae15c28.zip
Cleanup
-rw-r--r--README.md17
-rw-r--r--servo/templates/admin/statuses/remove.html6
-rwxr-xr-xservo/templates/generic/delete.html12
-rwxr-xr-xservo/templates/notes/search.html6
-rwxr-xr-xservo/templates/orders/toolbar.html4
-rw-r--r--servo/views/admin.py43
-rw-r--r--servo/views/checkin.py18
-rw-r--r--servo/views/device.py2
-rw-r--r--servo/views/gsx.py16
-rw-r--r--servo/views/note.py11
-rw-r--r--servo/views/purchases.py17
11 files changed, 76 insertions, 76 deletions
diff --git a/README.md b/README.md
index 6877ed0..1c3a016 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,5 @@
Introduction
============
-
Servo is a service management system for Authorised Apple Service Providers. It allows you to run your entire service business from within the same interface. Originally created in 2012 it is being used by service providers both large and small all around Europe.
Main features include:
@@ -22,7 +21,6 @@ Main features include:
System Requirements
===================
-
The application is written in Python on top of the excellent [Django web framework](https://www.djangoproject.com) and depends on the latest stable versions of the following components for operation:
- PostgreSQL
@@ -34,7 +32,6 @@ The application is written in Python on top of the excellent [Django web framewo
Installation
============
-
Install PostgreSQL, nginx, memcached, rabbitMQ. Then install the necessary Python packages:
$ pip install -U -r requirements.pip
@@ -48,7 +45,6 @@ Then clone the code:
Configuration
=============
-
Edit local_settings.py (these are settings specific to your installation):
import logging
@@ -100,13 +96,11 @@ Then fire up your browser and got to http://localhost:8080/
The VMWare Image
================
-
You can also download a preconfigured VMWare image [here](http://files.servoapp.com/vmware/). Please read the included README files for instructions.
Updating
========
-
First, back up your database, then:
$ git pull origin master
@@ -117,15 +111,14 @@ After which you should restart your Servo instance.
Documentation
=============
-
End-user documentation for the system is available [here](https://docs.servoapp.com). A user-friendly list of changes is published [here](https://docs.servoapp.com/changelog/).
FAQ
===
-
-Q: Why use Django?
-A: Because it works. Django also has the best documentation of any framework I've seen (especially from from PHP and Zend Framework)
+- Q: Why use Django?
+- A: Because it works. Django also has the best documentation of any framework I've seen (especially coming from PHP and Zend Framework)
+----
+- Q: Why is Servo open-source?
+- A: Because it's a mission-critical application and open-sourcing it means that companies will always have access to it.
----
-Q: Why is Servo open-source?
-A: Because it's a mission-critical application and open-sourcing it means that companies will always have access to it.
diff --git a/servo/templates/admin/statuses/remove.html b/servo/templates/admin/statuses/remove.html
index 78385a6..1040017 100644
--- a/servo/templates/admin/statuses/remove.html
+++ b/servo/templates/admin/statuses/remove.html
@@ -2,15 +2,15 @@
{% load i18n %}
{% block header %}
- <h2>{% blocktrans with status.title as title %}Delete status "{{ title }}"?{% endblocktrans %}</h2>
+ {% blocktrans with status.title as title %}Delete status "{{ title }}"?{% endblocktrans %}
{% endblock header %}
{% block body %}
- <p>{% trans "This action cannot be undone." %}</p>
+ {% trans "This action cannot be undone." %}</p>
{% endblock body %}
{% block footer %}
- <form action="{{ action }}" method="post">
+ <form action="{{ request.path }}" method="post">
{% csrf_token %}
<button type="submit" class="btn btn-danger">{% trans "Delete" %}</button>
</form>
diff --git a/servo/templates/generic/delete.html b/servo/templates/generic/delete.html
index 0503ce5..a8fa789 100755
--- a/servo/templates/generic/delete.html
+++ b/servo/templates/generic/delete.html
@@ -2,16 +2,16 @@
{% load i18n %}
{% block header %}
- {{ title }}
+ {{ title }}
{% endblock header %}
{% block body %}
- {{ explanation }}
+ {{ explanation }}
{% endblock body %}
{% block footer %}
- <form method="post" action="{{ action }}">
- {% csrf_token %}
- <button type="submit" class="btn btn-danger">{% trans "Delete" %}</button>
- </form>
+<form method="post" action="{{ action|default:request.path }}">
+ {% csrf_token %}
+ <button type="submit" class="btn btn-danger">{% trans "Delete" %}</button>
+</form>
{% endblock footer %}
diff --git a/servo/templates/notes/search.html b/servo/templates/notes/search.html
index 023bb07..e9c1842 100755
--- a/servo/templates/notes/search.html
+++ b/servo/templates/notes/search.html
@@ -1,16 +1,14 @@
{% extends "notes/list_notes.html" %}
-{% load servo_tags %}
-{% load humanize %}
{% load i18n %}
{% block toolbar %}
- <a href="{% url 'notes-create' %}" class="btn"><i class="icon-plus"></i> {% trans "Create Note" %}</a>
+ <a href="{% url 'notes-create' %}" class="btn"><i class="icon-plus"></i> {% trans "New Note" %}</a>
{% endblock toolbar %}
{% block content %}
<div class="page-header">
- <h1>{{ title }} <small>{{ subtitle }}</small></h1>
+ <h2>{{ title }} <small>{{ subtitle }}</small></h2>
</div>
{% include "notes/search-results.html" %}
diff --git a/servo/templates/orders/toolbar.html b/servo/templates/orders/toolbar.html
index 40a1405..425833c 100755
--- a/servo/templates/orders/toolbar.html
+++ b/servo/templates/orders/toolbar.html
@@ -82,9 +82,9 @@
<li><a href="{% url 'orders-toggle_follow' order.pk %}">{% trans "Follow Order" %}</a></li>
{% endif %}
{% if perms.servo.add_order and perms.servo.copy_order %}
- <li><a href="{% url 'orders-copy_order' order.pk %}">{% trans "Copy Order" %}</a></li>
+ <li><a href="{% url 'orders-copy_order' order.pk %}">{% trans "Duplicate Order" %}</a></li>
{% else %}
- <li><a class="disabled" href="#">{% trans "Copy Order" %}</a></li>
+ <li><a class="disabled" href="#">{% trans "Duplicate Order" %}</a></li>
{% endif %}
<li><a href="{% url 'barcodes-view' order.code %}?f=svg" target="_blank">{% trans "Show Barcode" %}</a></li>
<li class="divider"></li>
diff --git a/servo/views/admin.py b/servo/views/admin.py
index 6a54a4f..ed9f4d8 100644
--- a/servo/views/admin.py
+++ b/servo/views/admin.py
@@ -76,12 +76,12 @@ def edit_gsx_account(request, pk=None):
@staff_member_required
def delete_gsx_account(request, pk=None):
- act = GsxAccount.objects.get(pk=pk)
+ act = get_object_or_404(GsxAccount, pk=pk)
if request.method == 'POST':
try:
act.delete()
messages.success(request, _("GSX account deleted"))
- except Exception, e:
+ except Exception as e:
messages.error(request, e)
return redirect(list_gsx_accounts)
@@ -138,7 +138,6 @@ def delete_checklist(request, pk):
messages.success(request, _('Checklist deleted'))
return redirect(checklists)
- action = str(request.path)
title = _('Really delete this checklist?')
explanation = _('This will also delete all checklist values.')
@@ -166,7 +165,7 @@ def edit_tag(request, type, pk=None):
if pk is None:
tag = Tag(type=type)
else:
- tag = Tag.objects.get(pk=pk)
+ tag = get_object_or_404(Tag, pk=pk)
TagForm = modelform_factory(Tag, exclude=[])
form = TagForm(instance=tag)
@@ -187,7 +186,7 @@ def edit_tag(request, type, pk=None):
@staff_member_required
def delete_tag(request, pk):
- tag = Tag.objects.get(pk=pk)
+ tag = get_object_or_404(Tag, pk=pk)
if request.method == 'POST':
tag.delete()
@@ -257,7 +256,7 @@ def edit_status(request, pk=None):
if pk is None:
status = Status()
else:
- status = Status.objects.get(pk=pk)
+ status = get_object_or_404(Status, pk=pk)
header = _(u'Statuses')
object_list = Status.objects.all()
@@ -276,8 +275,7 @@ def edit_status(request, pk=None):
@staff_member_required
def remove_status(request, pk):
- status = Status.objects.get(pk=pk)
- action = request.path
+ status = get_object_or_404(Status, pk=pk)
if request.method == 'POST':
status.delete()
@@ -328,7 +326,7 @@ def edit_field(request, type, pk=None):
@staff_member_required
def delete_field(request, pk=None):
- field = Property.objects.get(pk=pk)
+ field = get_object_or_404(Property, pk=pk)
if request.method == 'POST':
field.delete()
@@ -345,8 +343,10 @@ def delete_field(request, pk=None):
def list_templates(request):
object_list = Template.objects.all()
title = Template._meta.verbose_name_plural
+
if object_list.count() > 0:
return redirect(object_list[0].get_admin_url())
+
return render(request, "admin/templates/list_templates.html", locals())
@@ -356,7 +356,7 @@ def edit_template(request, pk=None):
if pk is None:
template = Template()
else:
- template = Template.objects.get(pk=pk)
+ template = get_object_or_404(Template, pk=pk)
form = TemplateForm(instance=template)
@@ -377,15 +377,14 @@ def edit_template(request, pk=None):
@staff_member_required
def delete_template(request, pk):
- template = Template.objects.get(pk=pk)
+ template = get_object_or_404(Template, pk=pk)
if request.method == 'POST':
template.delete()
messages.success(request, _(u'Template %s deleted') % template.title)
return redirect(list_templates)
- title = _('Really delete this template?')
- action = str(request.path)
+ title = _('Delete this template?')
return render(request, 'generic/delete.html', locals())
@@ -434,7 +433,7 @@ def edit_group(request, pk=None):
@staff_member_required
def delete_group(request, pk):
- group = Group.objects.get(pk=pk)
+ group = get_object_or_404(Group, pk=pk)
if request.method == "POST":
group.delete()
@@ -448,9 +447,12 @@ def delete_group(request, pk):
@staff_member_required
def delete_user(request, user_id):
- user = User.objects.get(pk=user_id)
+ user = get_object_or_404(User, pk=user_id)
if request.method == "POST":
+ if user == request.user:
+ messages.error(request, _('Deleting yourself is not allowed'))
+ return redirect(list_users)
try:
user.delete()
messages.success(request, _("User deleted"))
@@ -464,7 +466,7 @@ def delete_user(request, user_id):
@staff_member_required
def delete_user_token(request, user_id):
- user = User.objects.get(pk=user_id)
+ user = get_object_or_404(User, pk=user_id)
user.delete_tokens()
messages.success(request, _('API tokens deleted'))
return redirect(edit_user, user.pk)
@@ -514,6 +516,8 @@ def edit_user(request, pk=None):
if len(object_list) > 0:
header = _(u'%d users') % len(object_list)
+ can_delete = user != request.user
+
return render(request, "admin/users/form.html", locals())
@@ -557,7 +561,7 @@ def edit_location(request, pk=None):
@staff_member_required
def delete_location(request, pk):
- location = Location.objects.get(pk=pk)
+ location = get_object_or_404(Location, pk=pk)
if request.method == 'POST':
try:
@@ -570,7 +574,6 @@ def delete_location(request, pk):
title = _(u'Really delete this location?')
explanation = _(u'This will not delete the orders at this location')
- action = request.path
return render(request, 'generic/delete.html', locals())
@@ -594,7 +597,7 @@ def edit_queue(request, pk=None):
locations = request.user.locations.all()
form = QueueForm(initial={'locations': locations})
else:
- queue = Queue.objects.get(pk=pk)
+ queue = get_object_or_404(Queue, pk=pk)
form = QueueForm(instance=queue, initial={'users': queue.user_set.all()})
title = _(u'Queues')
@@ -629,7 +632,7 @@ def edit_queue(request, pk=None):
@staff_member_required
def delete_queue(request, pk=None):
- queue = Queue.objects.get(pk=pk)
+ queue = get_object_or_404(Queue, pk=pk)
if request.method == 'POST':
try:
diff --git a/servo/views/checkin.py b/servo/views/checkin.py
index 68e922f..da11318 100644
--- a/servo/views/checkin.py
+++ b/servo/views/checkin.py
@@ -15,6 +15,7 @@ from django.core.exceptions import ValidationError
from django.utils.translation import ugettext as _
from django.shortcuts import render, redirect, get_object_or_404
+from servo.lib.utils import json_response
from servo.views.order import put_on_paper
from servo.validators import apple_sn_validator
from servo.models import (User, Device, GsxAccount, Order,
@@ -148,13 +149,16 @@ def thanks(request, order):
def get_customer(request):
+ """
+ Returns the selected customer data
+ """
if not request.user.is_authenticated():
return
if not request.GET.get('c'):
return
- customer = Customer.objects.get(pk=request.GET['c'])
+ customer = get_object_or_404(Customer, pk=request.GET['c'])
request.session['checkin_customer'] = customer.pk
fdata = {'fname': customer.firstname}
@@ -166,7 +170,7 @@ def get_customer(request):
fdata['address'] = customer.street_address
fdata['postal_code'] = customer.zip_code
- return HttpResponse(json.dumps(fdata), content_type='application/json')
+ return json_response(fdata)
def status(request):
@@ -196,7 +200,7 @@ def status(request):
def print_confirmation(request, code):
- order = Order.objects.get(url_code=code)
+ order = get_object_or_404(Order, url_code=code)
return put_on_paper(request, order.pk)
@@ -359,18 +363,20 @@ def index(request):
# Checklists probably not configured
pass
- if request.GET.get('phone'):
+ phone = request.GET.get('phone')
+
+ if phone:
if not request.user.is_authenticated():
return
results = []
- for c in Customer.objects.filter(phone=request.GET['phone']):
+ for c in Customer.objects.filter(phone=phone):
title = '%s - %s' % (c.phone, c.name)
results.append({'id': c.pk, 'name': c.name, 'title': title})
- return HttpResponse(json.dumps(results), content_type='application/json')
+ return json_response(results)
if request.GET.get('sn'):
diff --git a/servo/views/device.py b/servo/views/device.py
index 55895bc..9a4a6fb 100644
--- a/servo/views/device.py
+++ b/servo/views/device.py
@@ -214,7 +214,7 @@ def diagnostics(request, pk):
msg = _('Diagnostics initiated - diags://%s') % res
order.notify("init_diags", msg, request.user)
messages.success(request, msg)
- except gsxws.GsxError, e:
+ except gsxws.GsxError as e:
messages.error(request, e)
return redirect(order)
diff --git a/servo/views/gsx.py b/servo/views/gsx.py
index ebd1952..ce2ad1d 100644
--- a/servo/views/gsx.py
+++ b/servo/views/gsx.py
@@ -28,7 +28,7 @@ class RepairDetails(object):
@permission_required("servo.change_order")
def register_return(request, part_id):
- part = ServicePart.objects.get(pk=part_id)
+ part = get_object_or_404(ServicePart, pk=part_id)
try:
part.register_for_return(request.user)
messages.success(request, _(u"Part %s updated") % part.order_item.code)
@@ -70,7 +70,7 @@ def return_label(request, repair, part):
"""
Returns the return label PDF for this repair and part
"""
- repair = Repair.objects.get(pk=repair)
+ repair = get_object_or_404(Repair, pk=repair)
try:
repair.connect_gsx(request.user)
@@ -86,7 +86,7 @@ def add_part(request, repair, part):
"""
Adds this part to this GSX repair
"""
- rep = Repair.objects.get(pk=repair)
+ rep = get_object_or_404(Repair, pk=repair)
soi = rep.order.serviceorderitem_set.get(pk=part)
if request.method == "POST":
@@ -108,8 +108,8 @@ def add_part(request, repair, part):
def remove_part(request, repair, part):
- rep = Repair.objects.get(pk=repair)
- part = ServicePart.objects.get(pk=part)
+ rep = get_object_or_404(Repair, pk=repair)
+ part = get_object_or_404(ServicePart, pk=part)
if request.method == "POST":
@@ -154,7 +154,7 @@ def check_parts_warranty(request, repair):
Checks this (new) repair warranty status
with the included device and parts
"""
- repair = Repair.objects.get(pk=repair)
+ repair = get_object_or_404(Repair, pk=repair)
parts = repair.order.get_parts()
try:
@@ -333,7 +333,7 @@ def copy_repair(request, pk):
"""
Duplicates a local GSX repair
"""
- repair = Repair.objects.get(pk=pk)
+ repair = get_object_or_404(Repair, pk=pk)
new_repair = repair.duplicate(request.user)
return redirect(edit_repair, new_repair.order_id, new_repair.pk)
@@ -342,7 +342,7 @@ def update_sn(request, pk, part):
"""
Updates the parts serial number
"""
- part = ServicePart.objects.get(pk=part)
+ part = get_object_or_404(ServicePart, pk=part)
try:
part.repair.connect_gsx(request.user)
diff --git a/servo/views/note.py b/servo/views/note.py
index a68312a..9eb2a4a 100644
--- a/servo/views/note.py
+++ b/servo/views/note.py
@@ -136,7 +136,7 @@ def edit(request, pk=None, order_id=None, parent=None, recipient=None, customer=
customer = order.customer_id
if customer is not None:
- customer = Customer.objects.get(pk=customer)
+ customer = get_object_or_404(Customer, pk=customer)
note.customer = customer
if order_id is None:
@@ -169,7 +169,7 @@ def edit(request, pk=None, order_id=None, parent=None, recipient=None, customer=
formset = AttachmentFormset(queryset=note.attachments.all())
if parent is not None:
- parent = Note.objects.get(pk=parent)
+ parent = get_object_or_404(Note, pk=parent)
note.parent = parent
note.body = parent.quote()
@@ -263,7 +263,7 @@ def render_template(request):
"""
content = ''
title = request.POST.get('title')
- tpl = Template.objects.get(title=title)
+ tpl = get_object_or_404(Template, title=title)
if request.session.get('current_order_id'):
tpl = template.Template(tpl.content)
@@ -319,7 +319,7 @@ def list_notes(request, kind="inbox"):
def view_note(request, kind, pk):
- note = Note.objects.get(pk=pk)
+ note = get_object_or_404(Note, pk=pk)
data = prep_list_view(request, kind)
data['title'] = note.subject
data['note'] = note
@@ -334,8 +334,9 @@ def search(request):
query = request.GET.get("q")
request.session['search_query'] = query
- title = _(u'Notes containing "%s"') % query
results = Note.objects.filter(body__icontains=query).order_by('-created_at')
+ title = _(u'%d search results for "%s"') % (results.count(), query,)
+
paginator = Paginator(results, 10)
page = request.GET.get("page")
diff --git a/servo/views/purchases.py b/servo/views/purchases.py
index 4b789ee..8d382e9 100644
--- a/servo/views/purchases.py
+++ b/servo/views/purchases.py
@@ -7,8 +7,8 @@ from django.forms.models import inlineformset_factory
from django.utils.translation import ugettext as _
-from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import permission_required
+from django.shortcuts import render, redirect, get_object_or_404
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.contrib import messages
@@ -76,7 +76,7 @@ def list_pos(request):
@permission_required("servo.change_purchaseorder")
def delete_from_po(request, pk, item_id):
# @TODO - decrement amount_ordered?
- po = PurchaseOrder.objects.get(pk=pk)
+ po = get_object_or_404(PurchaseOrder, pk=pk)
poi = PurchaseOrderItem.objects.get(pk=item_id)
poi.delete()
messages.success(request, _(u'Product %s removed' % poi.product.code))
@@ -85,8 +85,8 @@ def delete_from_po(request, pk, item_id):
@permission_required("servo.change_purchaseorder")
def add_to_po(request, pk, product_id):
- po = PurchaseOrder.objects.get(pk=pk)
- product = Product.objects.get(pk=product_id)
+ po = get_object_or_404(PurchaseOrder, pk=pk)
+ product = get_object_or_404(Product, pk=product_id)
po.add_product(product, 1, request.user)
messages.success(request, _(u"Product %s added" % product.code))
return redirect(edit_po, po.pk)
@@ -101,7 +101,6 @@ def view_po(request, pk):
@permission_required("servo.change_purchaseorder")
def edit_po(request, pk, item_id=None):
-
if pk is not None:
po = get_object_or_404(PurchaseOrder, pk=pk)
else:
@@ -181,7 +180,7 @@ def order_stock(request, po_id):
po.submit(request.user)
msg = _("Products ordered with confirmation %s" % po.confirmation)
messages.success(request, msg)
- except gsxws.GsxError, e:
+ except gsxws.GsxError as e:
messages.error(request, e)
return redirect(list_pos)
@@ -192,7 +191,7 @@ def order_stock(request, po_id):
@permission_required('servo.delete_purchaseorder')
def delete_po(request, po_id):
- po = PurchaseOrder.objects.get(pk=po_id)
+ po = get_object_or_404(PurchaseOrder, pk=po_id)
try:
po.delete()
messages.success(request, _("Purchase Order %s deleted" % po_id))
@@ -211,13 +210,13 @@ def create_po(request, product_id=None, order_id=None):
po.save()
if order_id is not None:
- po.sales_order = Order.objects.get(pk=order_id)
+ po.sales_order = get_object_or_404(Order, pk=order_id)
po.save()
for i in ServiceOrderItem.objects.filter(order_id=order_id):
po.add_product(i, amount=1, user=request.user)
if product_id is not None:
- product = Product.objects.get(pk=product_id)
+ product = get_object_or_404(Product, pk=product_id)
po.add_product(product, amount=1, user=request.user)
messages.success(request, _("Purchase Order %d created" % po.pk))