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/views/search.py | 366 +++++++++++++++++++++++++++++--------------------- 1 file changed, 212 insertions(+), 154 deletions(-) (limited to 'servo/views/search.py') 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