From 19444b3b1c3d80b860d9d749942b7d2558950bcb Mon Sep 17 00:00:00 2001 From: Filipp Lepalaan Date: Wed, 11 Nov 2015 15:43:55 +0200 Subject: Refactored searches into separate module --- servo/templates/customers/search.html | 6 +- servo/templates/default.html | 3 +- servo/templates/devices/search_gsx.html | 51 ++-- servo/templates/devices/search_gsx_parts.html | 46 +-- servo/templates/devices/search_gsx_results.html | 8 +- servo/templates/devices/view.html | 2 +- servo/templates/search/results/gsx_results.html | 2 +- servo/templates/search/spotlight.html | 41 ++- servo/templatetags/servo_tags.py | 7 - servo/urls/customer.py | 22 +- servo/urls/default.py | 1 + servo/urls/device.py | 11 - servo/urls/note.py | 1 - servo/urls/order.py | 1 - servo/urls/products.py | 21 +- servo/urls/sales.py | 1 - servo/urls/search.py | 28 +- servo/views/customer.py | 72 ++--- servo/views/device.py | 178 +----------- servo/views/invoices.py | 16 +- servo/views/note.py | 22 +- servo/views/order.py | 49 +--- servo/views/product.py | 37 +-- servo/views/search.py | 366 ++++++++++++++---------- 24 files changed, 357 insertions(+), 635 deletions(-) (limited to 'servo') diff --git a/servo/templates/customers/search.html b/servo/templates/customers/search.html index 53b416b..3fecaa4 100755 --- a/servo/templates/customers/search.html +++ b/servo/templates/customers/search.html @@ -12,9 +12,9 @@ {% block first_column %} {% endblock first_column %} diff --git a/servo/templates/default.html b/servo/templates/default.html index adcc592..8a62a4a 100755 --- a/servo/templates/default.html +++ b/servo/templates/default.html @@ -40,8 +40,9 @@
  • {% trans "Statistics" %}
  • diff --git a/servo/templates/devices/search_gsx.html b/servo/templates/devices/search_gsx.html index 4f06b81..007befe 100755 --- a/servo/templates/devices/search_gsx.html +++ b/servo/templates/devices/search_gsx.html @@ -3,39 +3,38 @@ {% block second_column %} {% block tabs %} - + {% endblock tabs %} {% block results %} - {% include "devices/search_gsx_results.html" %} + {% include "devices/search_gsx_results.html" %} {% endblock results %} - {% endblock second_column %} {% block media %} {% endblock media %} diff --git a/servo/templates/devices/search_gsx_parts.html b/servo/templates/devices/search_gsx_parts.html index 63bfdb9..48ba7a7 100755 --- a/servo/templates/devices/search_gsx_parts.html +++ b/servo/templates/devices/search_gsx_parts.html @@ -3,28 +3,28 @@ {% autoescape on %} {% for p in results %} - - {{ p.code }} - {{ p.title }}
    {{ p.eee_code|truncatechars:40 }} - {{ p.price_sales_exchange|currency }} - {{ p.price_sales_stock|currency }} - 0 - -
    - - - - -
    - - + + {{ p.code }} + {{ p.title }}
    {{ p.eee_code|truncatechars:40 }} + {{ p.price_sales_exchange|currency }} + {{ p.price_sales_stock|currency }} + 0 + +
    + + + + +
    + + {% endfor %} {% endautoescape %} diff --git a/servo/templates/devices/search_gsx_results.html b/servo/templates/devices/search_gsx_results.html index b7a0926..df92660 100755 --- a/servo/templates/devices/search_gsx_results.html +++ b/servo/templates/devices/search_gsx_results.html @@ -1,5 +1,5 @@ -
    -
    -
    -
    +
    +
    +
    +
    diff --git a/servo/templates/devices/view.html b/servo/templates/devices/view.html index fd6d3a9..51a30c1 100755 --- a/servo/templates/devices/view.html +++ b/servo/templates/devices/view.html @@ -66,7 +66,7 @@
    {% if device.is_apple_device %}
    -
    +
    diff --git a/servo/templates/search/results/gsx_results.html b/servo/templates/search/results/gsx_results.html index dc7fff5..0e4c890 100755 --- a/servo/templates/search/results/gsx_results.html +++ b/servo/templates/search/results/gsx_results.html @@ -1,4 +1,4 @@ -
    +
    diff --git a/servo/templates/search/spotlight.html b/servo/templates/search/spotlight.html index 3b3715c..f18eb43 100755 --- a/servo/templates/search/spotlight.html +++ b/servo/templates/search/spotlight.html @@ -3,35 +3,32 @@ {% load i18n %} {% block toolbar %} - {% trans "New Customer" %} {% endblock toolbar %} {% block first_column %} - {% endblock first_column %} {% block second_column %} + {% endblock second_column %} {% block footer %} -
  • {% trans "Home" %} /
  • {{ title }}
  • +
  • {% trans "Home" %} /
  • {{ title }}
  • {% endblock footer %} diff --git a/servo/templatetags/servo_tags.py b/servo/templatetags/servo_tags.py index 2b25e04..72cb7b0 100644 --- a/servo/templatetags/servo_tags.py +++ b/servo/templatetags/servo_tags.py @@ -43,13 +43,6 @@ def count_or_empty(queryset): return '' -@register.filter -def search_url(request): - "Returns the proper search URL" - prefix = request.path.split("/")[1] - return "/%s/search/" % prefix - - @register.filter def str_find(string, substr): return (string.find(substr) > -1) diff --git a/servo/urls/customer.py b/servo/urls/customer.py index f029325..9665aaf 100644 --- a/servo/urls/customer.py +++ b/servo/urls/customer.py @@ -6,24 +6,30 @@ urlpatterns = patterns( "servo.views.customer", url(r'^$', 'index', {'group': 'all'}, name="customers-list_all"), url(r'^find/$', 'find', name="customers-find"), - url(r'^search/$', 'search', name="customers-search"), url(r'^filter/$', 'filter', name="customers-filter"), url(r'^download/$', 'download', name="customers-download"), url(r'^download/(?P[\w\-]+)/$', 'download', name="customers-download"), url(r'^find/download$', 'download', name="customers-download_search"), url(r'^groups/add/$', 'edit_group', name="customers-create_group"), - url(r'^groups/(?P[\w\-]+)/edit/$', 'edit_group', name="customers-edit_group"), - url(r'^groups/(?P[\w\-]+)/delete/$', 'delete_group', name="customers-delete_group"), + url(r'^groups/(?P[\w\-]+)/edit/$', 'edit_group', + name="customers-edit_group"), + url(r'^groups/(?P[\w\-]+)/delete/$', 'delete_group', + name="customers-delete_group"), url(r'^(?P[\w\-]+)/$', 'index', name="customers-list"), url(r'^(?P[\w\-]+)/upload/$', 'upload', name="customers-upload"), url(r'^(?P[\w\-]+)/add/$', 'edit', name="customers-create_customer"), - url(r'^(?P[\w\-]+)/(?P\d+)/$', 'view', name="customers-view_customer"), - url(r'^(?P[\w\-]+)/(?P\d+)/edit/$', 'edit', name="customers-edit_customer"), - url(r'^(?P[\w\-]+)/(?P\d+)/delete/$', 'delete', name="customers-delete_customer"), + url(r'^(?P[\w\-]+)/(?P\d+)/$', 'view', + name="customers-view_customer"), + url(r'^(?P[\w\-]+)/(?P\d+)/edit/$', 'edit', + name="customers-edit_customer"), + url(r'^(?P[\w\-]+)/(?P\d+)/delete/$', 'delete', + name="customers-delete_customer"), url(r'^(?P\d+)/move/$', 'move', name="customers-move_customer"), - url(r'^(?P\d+)/move/(?P\d+)/$', 'move', name="customers-move_customer"), + url(r'^(?P\d+)/move/(?P\d+)/$', 'move', + name="customers-move_customer"), url(r'^(?P\d+)/merge/$', 'merge', name="customers-merge_customer"), - url(r'^(?P\d+)/merge/(?P\d+)/$', 'merge', name="customers-merge_customer"), + url(r'^(?P\d+)/merge/(?P\d+)/$', 'merge', + name="customers-merge_customer"), url(r'^(?P\d+)/new/$', 'edit', name="customers-create_contact"), url(r'^(\d+)/orders/(\d+)/$', 'add_order', name="customers-add_to_order"), url(r'^(?P\d+)/notes/$', 'notes', name="customers-list_notes"), diff --git a/servo/urls/default.py b/servo/urls/default.py index 35c1f05..d70d295 100644 --- a/servo/urls/default.py +++ b/servo/urls/default.py @@ -49,5 +49,6 @@ urlpatterns = patterns( (r'^kaboom/$', 'servo.views.error.report'), url(r'^home/', include('servo.urls.account')), + url(r'^search/', include('servo.urls.search')), ) diff --git a/servo/urls/device.py b/servo/urls/device.py index defef62..04839dc 100644 --- a/servo/urls/device.py +++ b/servo/urls/device.py @@ -4,7 +4,6 @@ from django.conf.urls import patterns, url from django.views.decorators.cache import cache_page from servo.views.order import create -from servo.views.device import get_gsx_search_results from servo.views.diagnostics import diagnostics, select_test, run_test @@ -12,7 +11,6 @@ urlpatterns = patterns( "servo.views.device", url(r'^$', 'index', name="devices-list"), - url(r'^search/$', 'search'), url(r'^find/$', "find", name="devices-find"), url(r'^add/$', "edit_device", name="devices-add"), @@ -27,14 +25,6 @@ urlpatterns = patterns( url(r'^(?P\d+)/orders/(?P\d+)/queue/(?P\d+)/parts/$', "parts", name="devices-parts"), - url(r'^search/gsx/(?P\w+)/(?P\w+)/(?P[~\w\s,\-\(\)/\.]+)/$', - "search_gsx", - name="devices-search_gsx"), - - url(r'^search/gsx/(?P\w+)/(?P\w+)/(?P[~\w\s,\-\(\)/\.]+)/$', - cache_page(60*15)(get_gsx_search_results), - name="devices-get_gsx_search_results"), - url(r'^choose/order/(\d+)/$', 'choose', name="devices-choose"), url(r'^upload/$', 'upload_devices', name="devices-upload_devices"), url(r'^(?P\d+)/orders/create/$', create, @@ -58,5 +48,4 @@ urlpatterns = patterns( "delete_device", name="devices-delete_device"), - url(r'^search$', 'search', name="devices-search"), ) diff --git a/servo/urls/note.py b/servo/urls/note.py index 4057f40..0e1b65c 100644 --- a/servo/urls/note.py +++ b/servo/urls/note.py @@ -5,7 +5,6 @@ from django.conf.urls import patterns, url urlpatterns = patterns( "servo.views.note", url(r'^$', 'list_notes', name="notes-list_notes"), - url(r'^search/$', 'search', name="notes-search"), url(r'^find/$', 'find', name="notes-find"), url(r'^templates/$', 'templates'), diff --git a/servo/urls/order.py b/servo/urls/order.py index 39badfa..c2a49a6 100644 --- a/servo/urls/order.py +++ b/servo/urls/order.py @@ -12,7 +12,6 @@ urlpatterns = patterns( url(r'^$', 'list_orders', name='orders-index'), url(r'^\?queue=(?P\d+)$', 'list_orders', name='orders-list_queue'), - url(r'^search/$', 'search', name="orders-search"), url(r'^batch/$', 'batch_process', name="orders-batch_process"), url(r'^download/$', 'download_results', name="orders-download_results"), diff --git a/servo/urls/products.py b/servo/urls/products.py index 9de2575..9c60baa 100644 --- a/servo/urls/products.py +++ b/servo/urls/products.py @@ -12,20 +12,18 @@ urlpatterns = patterns( url(r'^upload/parts/$', "upload_gsx_parts", name="products-upload_gsx_parts"), url(r'^update_price/(\d+)/$', "update_price", name="products-update_price"), - url(r'^all/(?P\d+)/$', "view_product", {'group': 'all'}, name="products-view_product"), + url(r'^all/(?P\d+)/$', "view_product", {'group': 'all'}, + name="products-view_product"), url(r'^(?P[\w\-/]*)/(?P\d+)/view/$', "view_product", name="products-view_product"), # Editing product categories url(r'^categories/create/$', "edit_category", name="products-create_category"), - url(r'^categories/(?P[\w\-]+)/edit/$', - "edit_category", + url(r'^categories/(?P[\w\-]+)/edit/$', "edit_category", name="products-edit_category"), - url(r'^categories/(?P[\w\-]+)/delete/$', - "delete_category", + url(r'^categories/(?P[\w\-]+)/delete/$', "delete_category", name="products-delete_category"), - url(r'^categories/(?P[\w\-]+)/create/$', - "edit_category", + url(r'^categories/(?P[\w\-]+)/create/$', "edit_category", name="products-create_category"), # Editing products @@ -37,15 +35,14 @@ urlpatterns = patterns( name="products-delete_product"), # Choosing a product for an order - url(r'^choose/order/(?P\d+)/$', "choose_product", name="products-choose"), + url(r'^choose/order/(?P\d+)/$', "choose_product", + name="products-choose"), url(r'^(?P[\w\-]+)/(?P[\w\-/]+)/create/$', "edit_product", name="products-create"), - url(r'^all/(?P[\w\-/]+)/view/$', - "view_product", {'group': 'all'}, + url(r'^all/(?P[\w\-/]+)/view/$', "view_product", {'group': 'all'}, name="products-view_product"), - url(r'^(?P[\w\-/]+)/new/$', - "edit_product", {'group': None}, + url(r'^(?P[\w\-/]+)/new/$', "edit_product", {'group': None}, name="products-create"), url(r'^code/(?P[\w\-/]+)/location/(?P\d+)/get_info/$', diff --git a/servo/urls/sales.py b/servo/urls/sales.py index 152a394..dd1d637 100644 --- a/servo/urls/sales.py +++ b/servo/urls/sales.py @@ -8,5 +8,4 @@ urlpatterns = patterns( url(r'^purchases/', include('servo.urls.purchases')), url(r'^shipments/', include('servo.urls.shipments')), url(r'^invoices/', include('servo.urls.invoices')), - url(r'^search/$', 'servo.views.product.search'), ) diff --git a/servo/urls/search.py b/servo/urls/search.py index 486bdcf..06278d6 100644 --- a/servo/urls/search.py +++ b/servo/urls/search.py @@ -3,27 +3,17 @@ from django.conf.urls import patterns, url from django.views.decorators.cache import cache_page -from servo.views.search import search_gsx +from servo.views.search import search_gsx, get_gsx_search_results urlpatterns = patterns( "servo.views.search", - url(r'^$', "spotlight", - name="search-spotlight"), - url(r'^gsx/(?P\w+)/$', "list_gsx", - name="search-gsx"), - url(r'^gsx/(?P\w+)/for/(?P\w+)/$', "list_gsx", - name="search-gsx"), - # /search/gsx/parts/?productName=iPod+Shuffle... - url(r'^gsx/(?P\w+)/(?P\w+)/(?P[~\w\s,\-\(\)/\.]+)/$', - cache_page(60*15)(search_gsx), + url(r'^$', "spotlight", name="search-spotlight"), + url(r'^customers/$', "customers", name="search-customers"), + url(r'^devices/(?P\w+)/(?P\w+)/(?P[~\w\s,\-\(\)/\.]+)/$', + "search_gsx", name="search-search_gsx"), - url(r'^gsx/(?P\w+)/results/$', "view_gsx_results", - name="search-gsx_results"), - url(r'^notes/$', "list_notes"), - url(r'^products/$', "list_products"), - url(r'^orders/$', "list_orders"), - url(r'^customers/$', "list_customers"), - url(r'^devices/$', "list_devices"), - url(r'^gsx/$', "list_gsx"), - url(r'^articles/$', "list_articles"), + url(r'^gsx/(?P\w+)/(?P\w+)/(?P[~\w\s,\-\(\)/\.]+)/$', + #cache_page(60*15)(get_gsx_search_results), + get_gsx_search_results, + name="search-get_gsx_search_results"), ) diff --git a/servo/views/customer.py b/servo/views/customer.py index 9adb3e5..1372419 100644 --- a/servo/views/customer.py +++ b/servo/views/customer.py @@ -10,7 +10,8 @@ from django.forms.models import modelform_factory from django.utils.translation import ugettext as _ 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 servo.lib.utils import paginate from servo.models.note import Note from servo.models.order import Order @@ -29,6 +30,7 @@ def prepare_view(request, group='all'): title = _("Customers") customer_list = [] + search_hint = "customers" all_customers = Customer.objects.all().order_by('name') customer_count = all_customers.count() @@ -53,15 +55,7 @@ def prepare_view(request, group='all'): title = g.name page = request.GET.get('page') - paginator = Paginator(customer_list, 40) - - try: - customers = paginator.page(page) - except PageNotAnInteger: - customers = paginator.page(1) - except EmptyPage: - customers = paginator.page(paginator.num_pages) - + customers = paginate(customer_list, page, 40) groups = CustomerGroup.objects.all() return locals() @@ -80,8 +74,8 @@ def index(request, group='all'): @permission_required("servo.change_order") def add_order(request, customer_id, order_id): - order = Order.objects.get(pk=order_id) - customer = Customer.objects.get(pk=customer_id) + order = get_object_or_404(Order, pk=order_id) + customer = get_object_or_404(Customer, pk=customer_id) order.customer = customer order.save() @@ -95,19 +89,14 @@ def add_order(request, customer_id, order_id): def notes(request, pk, note_id=None): from servo.forms.note import NoteForm - customer = Customer.objects.get(pk=pk) + customer = get_object_or_404(Customer, pk=pk) form = NoteForm(initial={'recipient': customer.name}) return render(request, "notes/form.html", {'form': form}) def view(request, pk, group='all'): - try: - c = Customer.objects.get(pk=pk) - except Customer.DoesNotExist: - messages.error(request, _('Customer not found')) - return redirect(index) - + c = get_object_or_404(Customer, pk=pk) data = prepare_view(request, group) data['title'] = c.name @@ -150,7 +139,7 @@ def edit_group(request, group='all'): @permission_required("servo.change_customer") def delete_group(request, group): - group = CustomerGroup.objects.get(slug=group) + group = get_object_or_404(CustomerGroup, slug=group) if request.method == "POST": group.delete() @@ -178,7 +167,7 @@ def edit(request, pk=None, parent_id=None, group='all'): form = CustomerForm(initial={'name': name}) if pk is not None: - customer = Customer.objects.get(pk=pk) + customer = get_object_or_404(Customer, pk=pk) form = CustomerForm(instance=customer) if parent_id is not None: @@ -233,7 +222,7 @@ def edit(request, pk=None, parent_id=None, group='all'): @permission_required("servo.delete_customer") def delete(request, pk=None, group='all'): - customer = Customer.objects.get(pk=pk) + customer = get_object_or_404(Customer, pk=pk) if request.method == "POST": customer.delete() @@ -254,7 +243,7 @@ def merge(request, pk, target=None): - invoices Deletes the source customer """ - customer = Customer.objects.get(pk=pk) + customer = get_object_or_404(Customer, pk=pk) title = _('Merge %s with') % customer.name if request.method == 'POST': @@ -281,7 +270,7 @@ def move(request, pk, new_parent=None): """ Moves a customer under another customer """ - customer = Customer.objects.get(pk=pk) + customer = get_object_or_404(Customer, pk=pk) if new_parent is not None: if int(new_parent) == 0: @@ -304,28 +293,6 @@ def move(request, pk, new_parent=None): return render(request, "customers/move.html", locals()) -def search(request): - """ - Searches for customers from "spotlight" - """ - query = request.GET.get("q") - kind = request.GET.get('kind') - request.session['search_query'] = query - - customers = Customer.objects.filter( - Q(fullname__icontains=query) | Q(email__icontains=query) | Q(phone__contains=query) - ) - - if kind == 'company': - customers = customers.filter(is_company=True) - - if kind == 'contact': - customers = customers.filter(is_company=False) - - title = _('%d results for "%s"') % (customers.count(), query) - return render(request, "customers/search.html", locals()) - - def filter(request): """ Search for customers by name @@ -380,14 +347,7 @@ def find(request): title = _('Search for customers') page = request.GET.get('page') - paginator = Paginator(results, 50) - - try: - customers = paginator.page(page) - except PageNotAnInteger: - customers = paginator.page(1) - except EmptyPage: - customers = paginator.page(paginator.num_pages) + customers = paginate(results, page, 50) return render(request, "customers/find.html", locals()) @@ -430,7 +390,9 @@ def create_message(request, pk): def upload(request, group='all'): - + """ + Uploads customer data in CSV format + """ action = request.path form = CustomerUploadForm() diff --git a/servo/views/device.py b/servo/views/device.py index d828e47..f52af8f 100644 --- a/servo/views/device.py +++ b/servo/views/device.py @@ -11,8 +11,8 @@ from django.shortcuts import render, redirect, get_object_or_404 from django.utils.translation import ugettext as _ from django.template.defaultfilters import slugify from django.views.decorators.cache import cache_page -from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger +from servo.lib.utils import paginate from servo.models import Device, Order, Product, GsxAccount, ServiceOrderItem from servo.forms.devices import DeviceForm, DeviceUploadForm, DeviceSearchForm @@ -46,6 +46,7 @@ def model_from_slug(product_line, model=None): def prep_list_view(request, product_line=None, model=None): title = _('Devices') + search_hint = "devices" all_devices = Device.objects.all() product_lines = gsxws.products.models() @@ -66,15 +67,7 @@ def prep_list_view(request, product_line=None, model=None): all_devices = all_devices.filter(slug=model) page = request.GET.get('page') - paginator = Paginator(all_devices, 50) - - try: - devices = paginator.page(page) - except PageNotAnInteger: - devices = paginator.page(1) - except EmptyPage: - devices = paginator.page(paginator.num_pages) - + devices = paginate(all_devices, page, 50) return locals() @@ -168,160 +161,6 @@ def view_device(request, pk, product_line=None, model=None): return render(request, "devices/view.html", data) -def get_gsx_search_results(request, what, param, query): - """ - The second phase of a GSX search. - There should be an active GSX session open at this stage. - """ - data = {} - results = [] - query = query.upper() - device = Device(sn=query) - error_template = "search/results/gsx_error.html" - - # @TODO: this isn't a GSX search. Move it somewhere else. - if what == "orders": - try: - if param == 'serialNumber': - device = Device.objects.get(sn__exact=query) - if param == 'alternateDeviceId': - device = Device.objects.get(imei__exact=query) - except (Device.DoesNotExist, ValueError,): - return render(request, "search/results/gsx_notfound.html") - - orders = device.order_set.all() - return render(request, "orders/list.html", locals()) - - if what == "warranty": - # Update wty info if been here before - try: - device = Device.objects.get(sn__exact=query) - device.update_gsx_details() - except Exception: - try: - device = Device.from_gsx(query) - except Exception as e: - return render(request, error_template, {'message': e}) - - results.append(device) - - # maybe it's a device we've already replaced... - try: - soi = ServiceOrderItem.objects.get(sn__iexact=query) - results[0].repeat_service = soi.order - except ServiceOrderItem.DoesNotExist: - pass - - if what == "parts": - # looking for parts - if param == "partNumber": - # ... with a part number - part = gsxws.Part(partNumber=query) - - try: - partinfo = part.lookup() - except gsxws.GsxError, e: - return render(request, error_template, {'message': e}) - - product = Product.from_gsx(partinfo) - cache.set(query, product) - results.append(product) - - if param == "serialNumber": - # ... with a serial number - try: - results = device.get_parts() - data['device'] = device - except Exception as e: - return render(request, error_template, {'message': e}) - - if param == "productName": - product = gsxws.Product(productName=query) - parts = product.parts() - for p in parts: - results.append(Product.from_gsx(p)) - - if what == "repairs": - # Looking for GSX repairs - if param == "serialNumber": - # ... with a serial number - try: - device = gsxws.Product(query) - #results = device.repairs() - # @TODO: move the encoding hack to py-gsxws - for i, p in enumerate(device.repairs()): - d = {'purchaseOrderNumber': p.purchaseOrderNumber} - d['repairConfirmationNumber'] = p.repairConfirmationNumber - d['createdOn'] = p.createdOn - d['customerName'] = p.customerName.encode('utf-8') - d['repairStatus'] = p.repairStatus - results.append(d) - except gsxws.GsxError, e: - return render(request, "search/results/gsx_notfound.html") - - elif param == "dispatchId": - # ... with a repair confirmation number - repair = gsxws.Repair(number=query) - try: - results = repair.lookup() - except gsxws.GsxError as message: - return render(request, error_template, locals()) - - return render(request, "devices/search_gsx_%s.html" % what, locals()) - - -def search_gsx(request, what, param, query): - """ - The first phase of a GSX search - """ - title = _(u'Search results for "%s"') % query - - try: - act = request.session.get("gsx_account") - act = None - if act is None: - GsxAccount.default(user=request.user) - else: - act.connect(request.user) - except gsxws.GsxError as message: - return render(request, "devices/search_gsx_error.html", locals()) - - if request.is_ajax(): - if what == "parts": - try: - dev = Device.from_gsx(query) - products = dev.get_parts() - return render(request, "devices/parts.html", locals()) - except gsxws.GsxError as message: - return render(request, "search/results/gsx_error.html", locals()) - - return get_gsx_search_results(request, what, param, query) - - return render(request, "devices/search_gsx.html", locals()) - - -def search(request): - """ - Searching for devices from the main navbar - """ - query = request.GET.get("q", '').strip() - request.session['search_query'] = query - - query = query.upper() - valid_arg = gsxws.validate(query) - - if valid_arg in ('serialNumber', 'alternateDeviceId',): - return redirect(search_gsx, "warranty", valid_arg, query) - - devices = Device.objects.filter( - Q(sn__icontains=query) | Q(description__icontains=query) - ) - - title = _(u'Devices matching "%s"') % query - - return render(request, "devices/search.html", locals()) - - def find(request): """ Searching for device from devices/find @@ -348,16 +187,9 @@ def find(request): results = results.filter(created_at__range=[fdata['date_start'], fdata['date_end']]) - paginator = Paginator(results, 100) page = request.GET.get("page") - - try: - devices = paginator.page(page) - except PageNotAnInteger: - devices = paginator.page(1) - except EmptyPage: - devices = paginator.page(paginator.num_pages) - + devices = paginate(results, page, 100) + return render(request, "devices/find.html", locals()) diff --git a/servo/views/invoices.py b/servo/views/invoices.py index 6b77c8b..639515c 100644 --- a/servo/views/invoices.py +++ b/servo/views/invoices.py @@ -7,8 +7,8 @@ from django.utils.translation import ugettext as _ from django.forms.models import inlineformset_factory 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 servo.lib.utils import paginate from servo.forms.invoices import * from servo.models import Order, Invoice, Payment, PurchaseOrder @@ -57,24 +57,16 @@ def invoices(request): if fdata.get('service_order'): invoices = invoices.filter(order__code__exact=fdata['service_order']) - page = request.GET.get('page') data['total'] = invoices.aggregate(Sum('total_net')) data['total_paid'] = invoices.exclude(paid_at=None).aggregate(Sum('total_net')) pos = PurchaseOrder.objects.filter(created_at__range=[start_date, end_date]) data['total_purchases'] = pos.aggregate(Sum('total')) - paginator = Paginator(invoices, 50) - - try: - invoices = paginator.page(page) - except PageNotAnInteger: - invoices = paginator.page(1) - except EmptyPage: - invoices = paginator.page(paginator.num_pages) - + page = request.GET.get('page') data['form'] = form data['invoices'] = invoices - + data['invoices'] = paginate(invoices, page, 50) + return render(request, "invoices/index.html", data) diff --git a/servo/views/note.py b/servo/views/note.py index 4793e17..2ea6a14 100644 --- a/servo/views/note.py +++ b/servo/views/note.py @@ -81,6 +81,7 @@ def prep_list_view(request, kind): data['kind'] = kind data['notes'] = notes + data['search_hint'] = "notes" data['inbox_count'] = Note.objects.filter(order=None).count() return data @@ -331,27 +332,6 @@ def view_note(request, kind, pk): return render(request, "notes/view_note.html", data) -def search(request): - query = request.GET.get("q") - request.session['search_query'] = 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") - - try: - notes = paginator.page(page) - except PageNotAnInteger: - notes = paginator.page(1) - except EmptyPage: - notes = paginator.page(paginator.num_pages) - - return render(request, "notes/search.html", locals()) - - def find(request): form = NoteSearchForm(request.GET) results = Note.objects.none() diff --git a/servo/views/order.py b/servo/views/order.py index 3c284fb..a12fec2 100644 --- a/servo/views/order.py +++ b/servo/views/order.py @@ -22,7 +22,8 @@ from django.shortcuts import render, redirect, get_object_or_404 from django.views.decorators.csrf import csrf_exempt from django.contrib.auth.decorators import permission_required -from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger + +from servo.lib.utils import paginate from servo.models.order import * from servo.forms.orders import * @@ -137,18 +138,10 @@ def prepare_list_view(request, args): orders = orders.filter(status_limit_yellow__lte=now) page = request.GET.get("page") - paginator = Paginator(orders.distinct(), 100) - - try: - order_pages = paginator.page(page) - except PageNotAnInteger: - order_pages = paginator.page(1) - except EmptyPage: - order_pages = paginator.page(paginator.num_pages) data['form'] = form data['queryset'] = orders - data['orders'] = order_pages + data['orders'] = paginate(orders.distinct(), page, 100) data['subtitle'] = _("%d search results") % orders.count() return data @@ -888,43 +881,9 @@ def remove_customer(request, pk, customer_id): return render(request, "orders/remove_customer.html", data) -def search(request): - query = request.GET.get("q") - - if not query or len(query) < 3: - messages.error(request, _('Search query is too short')) - return redirect(list_orders) - - request.session['search_query'] = query - - # Redirect Order ID:s to the order - try: - order = Order.objects.get(code__iexact=query) - return redirect(order) - except Order.DoesNotExist: - pass - - orders = Order.objects.filter( - Q(code=query) | Q(devices__sn__contains=query) | - Q(customer__fullname__icontains=query) | - Q(customer__phone__contains=query) | - Q(repair__confirmation=query) | - Q(repair__reference=query) - ) - - data = { - 'title': _('Orders'), - 'subtitle': _(u'%d results for "%s"') % (orders.count(), query) - } - - data['orders'] = orders.distinct() - - return render(request, "orders/index.html", data) - - @permission_required("servo.add_order") def copy_order(request, pk): - order = Order.objects.get(pk=pk) + order = get_object_or_404(Order, pk=pk) new_order = order.duplicate(request.user) return redirect(new_order) diff --git a/servo/views/product.py b/servo/views/product.py index 01f551b..53213e2 100644 --- a/servo/views/product.py +++ b/servo/views/product.py @@ -14,7 +14,7 @@ from django.forms.models import inlineformset_factory from django.contrib.contenttypes.models import ContentType from django.contrib.auth.decorators import permission_required -from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger +from servo.lib.utils import paginate from servo.models import (Attachment, TaggedItem, Product, ProductCategory, @@ -28,6 +28,7 @@ def prep_list_view(request, group='all'): Prepares the product list view """ title = _("Products") + search_hint = "products" all_products = Product.objects.all() categories = ProductCategory.objects.all() @@ -71,14 +72,7 @@ def prep_list_view(request, group='all'): title += u" / %s" % group.title page = request.GET.get("page") - paginator = Paginator(all_products.distinct(), 25) - - try: - products = paginator.page(page) - except PageNotAnInteger: - products = paginator.page(1) - except EmptyPage: - products = paginator.page(paginator.num_pages) + products = paginate(all_products.distinct(), page, 25) return locals() @@ -320,31 +314,6 @@ def delete_product(request, pk, group): return render(request, 'products/remove.html', locals()) -def search(request): - - query = request.GET.get("q") - request.session['search_query'] = query - - results = Product.objects.filter( - Q(code__icontains=query) | Q(title__icontains=query) | Q(eee_code__icontains=query) - ) - - paginator = Paginator(results, 100) - page = request.GET.get("page") - - try: - products = paginator.page(page) - except PageNotAnInteger: - products = paginator.page(1) - except EmptyPage: - products = paginator.page(paginator.num_pages) - - title = _(u'Search results for "%s"') % query - group = ProductCategory(title=_('All'), slug='all') - - return render(request, 'products/search.html', locals()) - - def view_product(request, pk=None, code=None, group=None): product = Product() diff --git a/servo/views/search.py b/servo/views/search.py index 02eac99..30e1496 100644 --- a/servo/views/search.py +++ b/servo/views/search.py @@ -6,225 +6,283 @@ import gsxws from django.db.models import Q from django.core.cache import cache from django.shortcuts import render, redirect -from django.utils.translation import ugettext as _ from django.core.urlresolvers import reverse +from django.utils.translation import ugettext as _ from django.http import QueryDict, HttpResponseRedirect -from servo.models.note import Note -from servo.models.wiki import Article -from servo.models.device import Device -from servo.models.product import Product -from servo.models.common import GsxAccount -from servo.models.purchases import PurchaseOrder -from servo.models.order import Order, ServiceOrderItem - - -def results_redirect(view, data): - q = QueryDict('', mutable=True) - q['q'] = data['query'] - query_str = q.urlencode() - url = reverse(view, args=[data['what']]) - return HttpResponseRedirect("%s?%s" % (url, query_str)) - - -def prepare_result_view(request): - - query = request.GET.get('q') - - data = {'title': _('Search results for "%s"' % query)} - - data['gsx_type'] = gsxws.validate(query.upper()) - data['query'] = query - data['tag_id'] = None - data['cat_id'] = None # Product category - data['group'] = 'all' # customer group - - return data, query - +from servo.lib.utils import paginate +from servo.models import (Note, Device, Product, + GsxAccount, PurchaseOrder, Order, + ServiceOrderItem, Customer, ProductCategory,) -def list_gsx(request, what="warranty"): - data, query = prepare_result_view(request) - data['what'] = what - return render(request, "search/results/gsx.html", data) +def search_gsx(request, what, param, query): + """ + The first phase of a GSX search. Sets up the GSX connection. + """ + title = _(u'Search results for "%s"') % query -def search_gsx(request, what, arg, value): - if request.is_ajax(): - - if what == "parts" and value != "None": - results = [] + try: + act = request.session.get("gsx_account") + act = None + if act is None: GsxAccount.default(user=request.user) + else: + act.connect(request.user) + except gsxws.GsxError as message: + return render(request, "devices/search_gsx_error.html", locals()) - try: - product = gsxws.Product(productName=value) - parts = product.parts() - for p in parts: - results.append(Product.from_gsx(p)) - except gsxws.GsxError, e: - data = {'message': e} - return render(request, "search/results/gsx_error.html", data) - - data = {'results': results} - - return render(request, "search/results/gsx_%s.html" % what, data) + if request.is_ajax(): + return get_gsx_search_results(request, what, param, query) - data = {arg: value} - return render(request, "search/gsx_results.html", data) + return render(request, "devices/search_gsx.html", locals()) -def view_gsx_results(request, what="warranty"): +def get_gsx_search_results(request, what, param, query): """ - Searches for something from GSX. Defaults to warranty lookup. - GSX search strings are always UPPERCASE. + The second phase of a GSX search. + There should be an active GSX session open at this stage. """ - results = list() - data, query = prepare_result_view(request) - query = query.upper() - + data = {} + results = [] + query = query.upper() + device = Device(sn=query) error_template = "search/results/gsx_error.html" - if data['gsx_type'] == "dispatchId": - what = "repairs" - - if data['gsx_type'] == "partNumber": - what = "parts" - - data['what'] = what - gsx_type = data['gsx_type'] - - try: - if request.session.get("current_queue"): - queue = request.session['current_queue'] - GsxAccount.default(request.user, queue) - else: - GsxAccount.default(request.user) - except gsxws.GsxError, e: - error = {'message': e} - return render(request, error_template, error) - - if gsx_type == "serialNumber" or "alternateDeviceId": + # @TODO: this isn't a GSX search. Move it somewhere else. + if what == "orders": try: - device = Device.objects.get(sn=query) - except Device.DoesNotExist: - device = Device(sn=query) + if param == 'serialNumber': + device = Device.objects.get(sn__exact=query) + if param == 'alternateDeviceId': + device = Device.objects.get(imei__exact=query) + except (Device.DoesNotExist, ValueError,): + return render(request, "search/results/gsx_notfound.html") + + orders = device.order_set.all() + return render(request, "orders/list.html", locals()) if what == "warranty": - if cache.get(query): - result = cache.get(query) - else: + # Update wty info if been here before + try: + device = Device.objects.get(sn__exact=query) + device.update_gsx_details() + except Exception: try: - result = Device.from_gsx(query) - except gsxws.GsxError, e: - error = {'message': e} - return render(request, error_template, error) + device = Device.from_gsx(query) + except Exception as e: + return render(request, error_template, {'message': e}) - if re.match(r'iPhone', result.description): - result.activation = device.get_activation() + results.append(device) - results.append(result) + # maybe it's a device we've already replaced... + try: + soi = ServiceOrderItem.objects.get(sn__iexact=query) + results[0].repeat_service = soi.order + except ServiceOrderItem.DoesNotExist: + pass if what == "parts": # looking for parts - if gsx_type == "partNumber": + if param == "partNumber": # ... with a part number part = gsxws.Part(partNumber=query) try: partinfo = part.lookup() - except gsxws.GsxError, e: - error = {'message': e} - return render(request, error_template, error) + except gsxws.GsxError as e: + return render(request, error_template, {'message': e}) product = Product.from_gsx(partinfo) cache.set(query, product) results.append(product) - else: - # ... with a serial number + + if param == "serialNumber": try: - results = device.get_parts() - data['device'] = device - except Exception, e: - error = {'message': e} - return render(request, error_template, error) + dev = Device.from_gsx(query) + products = dev.get_parts() + return render(request, "devices/parts.html", locals()) + except gsxws.GsxError as message: + return render(request, "search/results/gsx_error.html", locals()) + + if param == "productName": + product = gsxws.Product(productName=query) + parts = product.parts() + for p in parts: + results.append(Product.from_gsx(p)) if what == "repairs": # Looking for GSX repairs - if gsx_type == "serialNumber": + if param == "serialNumber": # ... with a serial number try: device = gsxws.Product(query) - results = device.repairs() - except gsxws.GsxError, e: + #results = device.repairs() + # @TODO: move the encoding hack to py-gsxws + for i, p in enumerate(device.repairs()): + d = {'purchaseOrderNumber': p.purchaseOrderNumber} + d['repairConfirmationNumber'] = p.repairConfirmationNumber + d['createdOn'] = p.createdOn + d['customerName'] = p.customerName.encode('utf-8') + d['repairStatus'] = p.repairStatus + results.append(d) + except gsxws.GsxError as e: return render(request, "search/results/gsx_notfound.html") - elif gsx_type == "dispatchId": + elif param == "dispatchId": # ... with a repair confirmation number repair = gsxws.Repair(number=query) try: results = repair.lookup() - except gsxws.GsxError, e: - error = {'message': e} - return render(request, error_template, error) + except gsxws.GsxError as message: + return render(request, error_template, locals()) - if what == "repair_details": - repair = gsxws.Repair(number=query) - results = repair.details() - return render(request, "search/results/gsx_repair_details.html", results) + return render(request, "devices/search_gsx_%s.html" % what, locals()) - # Cache the results for quicker access later - cache.set('%s-%s' % (what, query), results) - data['results'] = results - return render(request, "search/results/gsx_%s.html" % what, data) +def products(request): + """ + Searches our local inventory + """ + query = request.GET.get("q") + request.session['search_query'] = query -def list_products(request): - data, query = prepare_result_view(request) - data['products'] = Product.objects.filter( - Q(code__icontains=query) | Q(title__icontains=query) + results = Product.objects.filter( + Q(code__icontains=query) | Q(title__icontains=query) | Q(eee_code__icontains=query) ) - return render(request, "search/results/products.html", data) + page = request.GET.get("page") + products = paginate(results, page, 50) + title = _(u'Search results for "%s"') % query + group = ProductCategory(title=_('All'), slug='all') -def list_notes(request): - data, query = prepare_result_view(request) - data['notes'] = Note.objects.filter(body__icontains=query) - return render(request, "search/results/notes.html", data) + return render(request, 'products/search.html', locals()) -def spotlight(request): +def orders(request): """ - Searches for anything and redirects to the "closest" result view. - GSX searches are done separately. + Searches local service orders """ - data, query = prepare_result_view(request) - data['what'] = "warranty" + query = request.GET.get("q") - if Order.objects.filter(customer__name__icontains=query).exists(): - return list_orders(request) + if not query or len(query) < 3: + messages.error(request, _('Search query is too short')) + return redirect(list_orders) - if data['gsx_type'] == "serialNumber": - try: - device = Device.objects.get(sn=query) - return redirect(device) - except Device.DoesNotExist: - return results_redirect("search-gsx", data) + request.session['search_query'] = query - data['parts'] = ServiceOrderItem.objects.filter(sn__icontains=query) + # Redirect Order ID:s to the order + try: + order = Order.objects.get(code__iexact=query) + return redirect(order) + except Order.DoesNotExist: + pass + + orders = Order.objects.filter( + Q(code=query) | Q(devices__sn__contains=query) | + Q(customer__fullname__icontains=query) | + Q(customer__phone__contains=query) | + Q(repair__confirmation=query) | + Q(repair__reference=query) + ) - if gsxws.validate(query, "dispatchId"): - try: - po = PurchaseOrder.objects.get(confirmation=query) - data['orders'] = [po.sales_order] - except PurchaseOrder.DoesNotExist: - pass + data = { + 'title': _('Orders'), + 'subtitle': _(u'%d results for "%s"') % (orders.count(), query) + } + + page = request.GET.get('page') + data['orders'] = paginate(orders.distinct(), page, 100) + + return render(request, "orders/index.html", data) + + +def customers(request): + """ + Searches for customers from "spotlight" + """ + query = request.GET.get("q") + kind = request.GET.get('kind') + request.session['search_query'] = query + + customers = Customer.objects.filter( + Q(fullname__icontains=query) | Q(email__icontains=query) | Q(phone__contains=query) + ) + + if kind == 'company': + customers = customers.filter(is_company=True) + + if kind == 'contact': + customers = customers.filter(is_company=False) + + title = _('%d results for "%s"') % (customers.count(), query) + + return render(request, "customers/search.html", locals()) + + +def devices(request): + """ + Searching for devices from the main navbar + """ + query = request.GET.get("q", '').strip() + request.session['search_query'] = query + + query = query.upper() + valid_arg = gsxws.validate(query) + + if valid_arg in ('serialNumber', 'alternateDeviceId',): + return redirect(search_gsx, "warranty", valid_arg, query) - data['products'] = Product.objects.filter( - Q(code__icontains=query) | Q(title__icontains=query) + devices = Device.objects.filter( + Q(sn__icontains=query) | Q(description__icontains=query) ) - data['articles'] = Article.objects.filter(content__contains=query) + title = _(u'Devices matching "%s"') % query + + return render(request, "devices/search.html", locals()) + + +def notes(request): + """ + Searches for local notes + """ + query = request.GET.get("q") + request.session['search_query'] = query + + results = Note.objects.filter(body__icontains=query).order_by('-created_at') + title = _(u'%d search results for "%s"') % (results.count(), query,) + notes = paginate(results, request.GET.get('page'), 10) + + return render(request, "notes/search.html", locals()) + + +def spotlight(request): + """ + Searches for anything and redirects to the "closest" result view. + GSX searches are done separately. + + To give good results, we must first "classify" the search query. + Some strings are easy to classify: + - serial numbers, repair confirmations, part numbers + Others, not so much: + - customer names, notes + """ + hint = request.GET.get('hint') + + if hint == 'orders': + return orders(request) + + if hint == 'customers': + return customers(request) + + if hint == 'devices': + return devices(request) + + if hint == 'notes': + return notes(request) - return render(request, "search/spotlight.html", data) + if hint == 'products': + return products(request) -- cgit v1.2.3