Polishing finding tickets by scanning and marking stuff as handed out/checked in.
This commit is contained in:
parent
7be4aa6545
commit
94a142f6b9
39
src/backoffice/static/js/ticket_scan.js
Normal file
39
src/backoffice/static/js/ticket_scan.js
Normal 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();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
|
@ -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 %}
|
||||
|
|
118
src/backoffice/templates/tickets/scan.html
Normal file
118
src/backoffice/templates/tickets/scan.html
Normal 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 %}
|
||||
|
|
@ -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 %}
|
||||
|
|
@ -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"),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue