From 94a142f6b905a7e9b9ec5844110fb160f46cf1a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=AD=C3=B0ir=20Valberg=20Gu=C3=B0mundsson?= Date: Sun, 4 Aug 2019 00:18:52 +0200 Subject: [PATCH] Polishing finding tickets by scanning and marking stuff as handed out/checked in. --- src/backoffice/static/js/ticket_scan.js | 39 +++++++ src/backoffice/templates/index.html | 6 +- src/backoffice/templates/tickets/scan.html | 118 +++++++++++++++++++++ src/backoffice/templates/user/search.html | 90 ---------------- src/backoffice/urls.py | 2 +- src/backoffice/views.py | 73 ++++++++++--- src/tickets/templates/pdf/ticket.html | 2 +- src/utils/templatetags/qrcode.py | 6 +- 8 files changed, 223 insertions(+), 113 deletions(-) create mode 100644 src/backoffice/static/js/ticket_scan.js create mode 100644 src/backoffice/templates/tickets/scan.html delete mode 100644 src/backoffice/templates/user/search.html diff --git a/src/backoffice/static/js/ticket_scan.js b/src/backoffice/static/js/ticket_scan.js new file mode 100644 index 00000000..d88243d3 --- /dev/null +++ b/src/backoffice/static/js/ticket_scan.js @@ -0,0 +1,39 @@ +document.addEventListener("DOMContentLoaded", () => { + "use strict"; + + const search_form = document.getElementById("search_form"); + const ticket_token_input = document.getElementById("ticket_token_input"); + const scan_again = document.getElementById("scan_again"); + + const check_in_input = document.getElementById("check_in_input"); + const hand_out_badge_input = document.getElementById("hand_out_badge_input"); + const check_in_form = document.getElementById("check_in_form"); + + search_form.onsubmit = submit; + + function submit(e) { + e.preventDefault(); + + if (ticket_token_input.value === "#clear") { + window.location.replace(window.location.pathname); + } else if (ticket_token_input.value === "#check-in") { + check_in_input.checked = true; + check_in_form.submit(); + } else if (ticket_token_input.value === "#hand-out-badge") { + hand_out_badge_input.checked = true; + check_in_form.submit(); + } else if (ticket_token_input.value.length === 65) { + search_form.submit(); + } else { + scan_again.removeAttribute("hidden"); + } + } + + document.addEventListener("keydown", event => { + if (event.key === "#") { + ticket_token_input.value = ""; + ticket_token_input.focus(); + } + }); + +}); diff --git a/src/backoffice/templates/index.html b/src/backoffice/templates/index.html index 19f97455..94e2be04 100644 --- a/src/backoffice/templates/index.html +++ b/src/backoffice/templates/index.html @@ -16,13 +16,13 @@
{% if perms.camps.infoteam_permission %}

Info Team

-

- User stuff + Scan tickets

- Use this to get everything related to a user + Use this to get scan tickets

{% endif %} diff --git a/src/backoffice/templates/tickets/scan.html b/src/backoffice/templates/tickets/scan.html new file mode 100644 index 00000000..692d74a4 --- /dev/null +++ b/src/backoffice/templates/tickets/scan.html @@ -0,0 +1,118 @@ +{% extends 'base.html' %} +{% load static from staticfiles %} +{% load qrcode %} + +{% block content %} + +
+ {% csrf_token %} + +
+ +
+

Scan the ticket!

+ + + + +
+ +
+ +
+ + +{% if ticket %} + + +
+ + + + + + + + +
+ Type: + + {{ ticket.ticket_type }} + +
+ Used?: + + {{ ticket.used }} + + {% if ticket.ticket_type.includes_badge %} +
+ Badge handed out?: + + {{ ticket.badge_handed_out }} + {% endif %} + + {% if ticket.product %} +
+ Product: + + {{ ticket.product }} +
+ Order: + + {{ ticket.order }} + {% endif %} + + {% if ticket.sponsor %} +
+ Sponsor + + {{ ticket.sponsor }} + {% endif %} + + +
+ +
+ +
{% csrf_token %} + + + +
+ +
+
+ {% qr_code "clear" %} +
+ + {% if not ticket.used %} +
+ {% qr_code "check-in" %} +
+ {% endif %} + + {% if ticket.ticket_type.includes_badge and not ticket.badge_handed_out %} +
+ {% qr_code "hand-out-badge" %} +
+ {% endif %} +
+{% endif %} + + + + + +{% endblock content %} + diff --git a/src/backoffice/templates/user/search.html b/src/backoffice/templates/user/search.html deleted file mode 100644 index 37afbdbd..00000000 --- a/src/backoffice/templates/user/search.html +++ /dev/null @@ -1,90 +0,0 @@ -{% extends 'base.html' %} -{% load static from staticfiles %} -{% load qrcode %} - -{% block content %} - -
- {% csrf_token %} - -
- -
-

Scan the ticket!

- - - - -
- -
- -
- -{% if ticket %} - {{ ticket }}
-
- Used?: {{ ticket.used }} - -
-
{% csrf_token %} - -
- -
-
- {% qr_code "clear" %} -
- -
- {% qr_code "check-in" %} -
- -{% endif %} - - - - - -{% endblock content %} - diff --git a/src/backoffice/urls.py b/src/backoffice/urls.py index a892343d..86a4d1a5 100644 --- a/src/backoffice/urls.py +++ b/src/backoffice/urls.py @@ -8,7 +8,7 @@ urlpatterns = [ path("", BackofficeIndexView.as_view(), name="index"), # infodesk path( - "user/", include([path("", SearchForUser.as_view(), name="user_interaction")]) + "tickets/", include([path("", ScanTicketsView.as_view(), name="scan_tickets")]) ), path("product_handout/", ProductHandoutView.as_view(), name="product_handout"), path("badge_handout/", BadgeHandoutView.as_view(), name="badge_handout"), diff --git a/src/backoffice/views.py b/src/backoffice/views.py index 08a4a4cd..b9817b80 100644 --- a/src/backoffice/views.py +++ b/src/backoffice/views.py @@ -546,28 +546,71 @@ class RevenueDetailView(CampViewMixin, EconomyTeamPermissionMixin, UpdateView): ) -class SearchForUser(TemplateView): - template_name = "user/search.html" +def _ticket_getter_by_token(token): + for ticket_class in [ShopTicket, SponsorTicket, DiscountTicket]: + try: + return ticket_class.objects.get(token=token), False + except ticket_class.DoesNotExist: + try: + return ticket_class.objects.get(badge_token=token), True + except ticket_class.DoesNotExist: + pass - def post(self, request, **kwargs): - check_in_ticket_id = request.POST.get("check_in_ticket_id") - if check_in_ticket_id: - ticket_to_check_in = ShopTicket.objects.get(pk=check_in_ticket_id) - ticket_to_check_in.used = True - ticket_to_check_in.save() - messages.info(request, "Ticket checked-in!") - return super().get(request, **kwargs) +def _ticket_getter_by_pk(pk): + for ticket_class in [ShopTicket, SponsorTicket, DiscountTicket]: + try: + return ticket_class.objects.get(pk=pk) + except ticket_class.DoesNotExist: + pass + + +class ScanTicketsView(TemplateView): + template_name = "tickets/scan.html" + + ticket = None def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - ticket_token = self.request.POST.get("ticket_token") - if ticket_token: - try: - ticket = ShopTicket.objects.get(token=ticket_token[1:]) + if self.ticket: + context["ticket"] = self.ticket + + elif "ticket_token" in self.request.POST: + + # Slice to get rid of the first character which is a '#' + ticket_token = self.request.POST.get("ticket_token")[1:] + + ticket, is_badge = _ticket_getter_by_token(ticket_token) + + if ticket: context["ticket"] = ticket - except ShopTicket.DoesNotExist: + context["is_badge"] = is_badge + else: messages.warning(self.request, "Ticket not found!") return context + + def post(self, request, **kwargs): + if 'check_in_ticket_id' in request.POST: + self.ticket = self.check_in_ticket(request) + elif 'badge_ticket_id' in request.POST: + self.ticket = self.hand_out_badge(request) + + return super().get(request, **kwargs) + + def check_in_ticket(self, request): + check_in_ticket_id = request.POST.get("check_in_ticket_id") + ticket_to_check_in = _ticket_getter_by_pk(check_in_ticket_id) + ticket_to_check_in.used = True + ticket_to_check_in.save() + messages.info(request, "Ticket checked-in!") + return ticket_to_check_in + + def hand_out_badge(self, request): + badge_ticket_id = request.POST.get('badge_ticket_id') + ticket_to_handout_badge_for = _ticket_getter_by_pk(badge_ticket_id) + ticket_to_handout_badge_for.badge_handed_out = True + ticket_to_handout_badge_for.save() + messages.info(request, "Badge marked as handed out!") + return ticket_to_handout_badge_for diff --git a/src/tickets/templates/pdf/ticket.html b/src/tickets/templates/pdf/ticket.html index 9da194af..260516ea 100644 --- a/src/tickets/templates/pdf/ticket.html +++ b/src/tickets/templates/pdf/ticket.html @@ -26,7 +26,7 @@
{% elif ticket.sponsor %}

Sponsor: {{ ticket.sponsor.name }}

- + {% endif %} {% if ticket.used %} diff --git a/src/utils/templatetags/qrcode.py b/src/utils/templatetags/qrcode.py index d09b8e5c..d989bc5e 100644 --- a/src/utils/templatetags/qrcode.py +++ b/src/utils/templatetags/qrcode.py @@ -11,13 +11,13 @@ register = template.Library() @register.simple_tag def qr_code(value): stream = io.BytesIO() - img = qrcode.make("#" + value, box_size=5) + img = qrcode.make("#" + value, box_size=7) img.save(stream, "PNG") data = base64.b64encode(stream.getvalue()) return mark_safe( - "
" + "
" '' - "
{}
" + "
{}
" "
".format(data.decode(), value) )