Polishing finding tickets by scanning and marking stuff as handed out/checked in.

This commit is contained in:
Víðir Valberg Guðmundsson 2019-08-04 00:18:52 +02:00
parent 7be4aa6545
commit 94a142f6b9
8 changed files with 223 additions and 113 deletions

View File

@ -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();
}
});
});

View File

@ -16,13 +16,13 @@
<div class="list-group">
{% if perms.camps.infoteam_permission %}
<h3>Info Team</h3>
<a href="{% url 'backoffice:user_interaction' camp_slug=camp.slug %}"
<a href="{% url 'backoffice:scan_tickets' camp_slug=camp.slug %}"
class="list-group-item">
<h4 class="list-group-item-heading">
User stuff
Scan tickets
</h4>
<p class="list-group-item-text">
Use this to get everything related to a user
Use this to get scan tickets
</p>
</a>
{% endif %}

View File

@ -0,0 +1,118 @@
{% extends 'base.html' %}
{% load static from staticfiles %}
{% load qrcode %}
{% block content %}
<form id="search_form" method="POST" action="">
{% csrf_token %}
<div class="row">
<div class="col-md-12">
<h3>Scan the ticket!</h3>
<input type="text" name="ticket_token" id="ticket_token_input" autocomplete="off" style="color: #fff; background: #fff; border: 0; height: 0; width: 0;"/>
<div id="scan_again" hidden>
Scan again!
<hr />
</div>
</div>
</div>
</form>
{% if ticket %}
<br />
<table class="table">
<tr>
<td>
<strong>Type:</strong>
<td>
{{ ticket.ticket_type }}
<tr>
<td>
<strong>Used?:</strong>
<td>
{{ ticket.used }}
{% if ticket.ticket_type.includes_badge %}
<tr>
<td>
<strong>Badge handed out?:</strong>
<td>
{{ ticket.badge_handed_out }}
{% endif %}
{% if ticket.product %}
<tr>
<td>
<strong>Product:</strong>
<td>
{{ ticket.product }}
<tr>
<td>
<strong>Order:</strong>
<td>
{{ ticket.order }}
{% endif %}
{% if ticket.sponsor %}
<tr>
<td>
<strong>Sponsor</strong>
<td>
{{ ticket.sponsor }}
{% endif %}
</table>
<hr />
<form id="check_in_form" method="POST" action="">{% csrf_token %}
<input type="checkbox"
name="check_in_ticket_id"
id="check_in_input"
value="{{ ticket.pk }}"
style="color: #fff; background: #fff; border: 0; height: 0; width: 0; opacity: 0;" />
<input type="checkbox"
name="badge_ticket_id"
id="hand_out_badge_input"
value="{{ ticket.pk }}"
style="color: #fff; background: #fff; border: 0; height: 0; width: 0; opacity: 0;" />
</form>
<div class="row">
<div class="col-md-4">
{% qr_code "clear" %}
</div>
{% if not ticket.used %}
<div class="col-md-4">
{% qr_code "check-in" %}
</div>
{% endif %}
{% if ticket.ticket_type.includes_badge and not ticket.badge_handed_out %}
<div class="col-md-4">
{% qr_code "hand-out-badge" %}
</div>
{% endif %}
</div>
{% endif %}
<script src="{% static 'js/ticket_scan.js' %}"></script>
{% endblock content %}

View File

@ -1,90 +0,0 @@
{% extends 'base.html' %}
{% load static from staticfiles %}
{% load qrcode %}
{% block content %}
<form id="search_form" method="POST" action="">
{% csrf_token %}
<div class="row">
<div class="col-md-12">
<h3>Scan the ticket!</h3>
<input type="text" name="ticket_token" id="ticket_token_input" autocomplete="off" style="color: #fff; background: #fff; border: 0; height: 0; width: 0;"/>
<span id="scan_again" hidden>Scan again!</span>
</div>
</div>
</form>
{% if ticket %}
{{ ticket }}<br />
<br />
Used?: {{ ticket.used }}
<hr />
<form id="check_in_form" method="POST" action="">{% csrf_token %}
<input type="input" name="check_in_ticket_id" id="check_in_input" value="{{ ticket.pk }}" style="color: #fff; background: #fff; border: 0; height: 0; width: 0;"/>
</form>
<div class="row">
<div class="col-md-6">
{% qr_code "clear" %}
</div>
<div class="col-md-6">
{% qr_code "check-in" %}
</div>
</divc>
{% endif %}
<script>
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 check_in_form = document.getElementById('check_in_form');
search_form.onsubmit = submit;
function submit(e) {
e.preventDefault();
console.log(ticket_token_input.value);
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.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();
}
});
});
</script>
{% endblock content %}

View File

@ -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"),

View File

@ -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

View File

@ -26,7 +26,7 @@
<br>
{% elif ticket.sponsor %}
<h3>Sponsor: {{ ticket.sponsor.name }} </h3>
<img src="{% static 'img/sponsors/' %}{{ sponsor.logo_filename }}"></img>
<img src="{% static 'img/sponsors/' %}{{ ticket.sponsor.logo_filename }}" />
{% endif %}
{% if ticket.used %}

View File

@ -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(
"<figure>"
"<figure style='text-align: center;'>"
'<img src="data:image/png;base64,{}" alt="">'
"<figcaption>{}</figcaption>"
"<figcaption style='text-align: center;'>{}</figcaption>"
"</figure>".format(data.decode(), value)
)