Add barcode to checkin

Add Code 128 format barcode to checkin
to cater for barcode scanners at registration.
Add flagged link to boarding pass to dashboard.
This commit is contained in:
Joel Addison 2024-04-12 21:08:17 +10:00
parent 5557802860
commit 84c3a48626
7 changed files with 58 additions and 2 deletions

View file

@ -66,6 +66,9 @@
{% flag "badge_preview" %} {% flag "badge_preview" %}
<a class="btn btn-info" role="button" href="{% url "user_badge" %}">Preview my badge</a> <a class="btn btn-info" role="button" href="{% url "user_badge" %}">Preview my badge</a>
{% endflag %} {% endflag %}
{% flag "view_boardingpass" %}
<a class="btn btn-info" role="button" href="{% url "boardingpass" %}">View Boarding Pass</a>
{% endflag %}
</div> </div>
</div> </div>
<div class="col-md-6 mb-3 mb-md-0"> <div class="col-md-6 mb-3 mb-md-0">

View file

@ -44,6 +44,9 @@ pinax-stripe==4.4.0
requests==2.24.0 requests==2.24.0
stripe==2.55.0 stripe==2.55.0
# Regidesk
python-barcode==0.15.1
# SASS Compiler and template tags # SASS Compiler and template tags
libsass==0.20.1 libsass==0.20.1
django-sass-processor==0.8.2 django-sass-processor==0.8.2

View file

@ -17,6 +17,8 @@ from django.db.models import Count
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
import pyqrcode import pyqrcode
from barcode import Code128
from barcode.writer import ImageWriter
from symposion import constants from symposion import constants
from symposion.text_parser import parse from symposion.text_parser import parse
@ -155,6 +157,19 @@ class CheckIn(models.Model):
return self._checkin_code_png return self._checkin_code_png
@property
def barcode(self):
"""Generates a Code 128 barcode of the checkin code.
Returns the base64 encoded raw PNG blob for the barcode.
"""
barcode = Code128(self.code, writer=ImageWriter())
barcode_io = BytesIO()
barcode.write(barcode_io)
barcode_io.seek(0)
b64_barcode = base64.b64encode(barcode_io.read()).decode('UTF-8')
return b64_barcode
@property @property
def venueless_token(self): def venueless_token(self):
"""Returns the Venueless JWT token for this checkin's code.""" """Returns the Venueless JWT token for this checkin's code."""

View file

@ -2,8 +2,9 @@
specific to each proposal: specific to each proposal:
<ul> <ul>
<li><code>{% templatetag openvariable %} user {% templatetag closevariable %}</code> e.g. {{ sample.user }}</li> <li><code>{% templatetag openvariable %} user {% templatetag closevariable %}</code> e.g. {{ sample.user }}</li>
<li><code>{% templatetag openvariable %} qrcode {% templatetag closevariable %}</code> e.g. <code>{% templatetag openvariable %} qrcode|safe {% templatetag closevariable %}</code> produces {{ sample.qrcode|safe }}</li> <li><code>{% templatetag openvariable %} qrcode {% templatetag closevariable %}</code> e.g. <code>{% templatetag openvariable %} qrcode|safe {% templatetag closevariable %}</code> produces Base64 encoded PNG data, to be used in an image tag. For example:<br> <img src="data:image/png;base64,{{ sample.qrcode|safe }}" /></li>
<li><code>{% templatetag openvariable %} qrcode_url {% templatetag closevariable %}</code> e.g. {{ sample.qrcode_url }}</li> <li><code>{% templatetag openvariable %} qrcode_url {% templatetag closevariable %}</code> e.g. {{ sample.qrcode_url }}</li>
<li><code>{% templatetag openvariable %} barcode {% templatetag closevariable %}</code> e.g. <code>{% templatetag openvariable %} barcode|safe {% templatetag closevariable %}</code> produces Base64 encoded PNG data, to be used in an image tag. For example:<br> <img src="data:image/png;base64,{{ sample.barcode|safe }}" /></li>
<li><code>{% templatetag openvariable %} code {% templatetag closevariable %}</code> e.g. {{ sample.code }}</li> <li><code>{% templatetag openvariable %} code {% templatetag closevariable %}</code> e.g. {{ sample.code }}</li>
<li><code>{% templatetag openvariable %} user.attendee.ticket_type {% templatetag closevariable %}</code> e.g. {{ sample.user.attendee.ticket_type }}</li> <li><code>{% templatetag openvariable %} user.attendee.ticket_type {% templatetag closevariable %}</code> e.g. {{ sample.user.attendee.ticket_type }}</li>
<li>The variables <code>invoices</code>, <code>items_pending</code>, <code>items_purchased</code>, <code>categories_missing</code> all return lists of the relevant things</code> <li>The variables <code>invoices</code>, <code>items_pending</code>, <code>items_purchased</code>, <code>categories_missing</code> all return lists of the relevant things</code>

View file

@ -13,5 +13,6 @@ urlpatterns = [
url(r"^checkin/$", views.CheckInLanding.as_view(), name="check_in_scanner"), url(r"^checkin/$", views.CheckInLanding.as_view(), name="check_in_scanner"),
url(r"^checkin/(?P<access_code>[A-Z0-9]{6})/$", views.check_in_overview, name="check_in_user_view"), url(r"^checkin/(?P<access_code>[A-Z0-9]{6})/$", views.check_in_overview, name="check_in_user_view"),
url(r"^checkin/([A-Z0-9]{6})/badge$", views.checken_in_badge, name="check_in_badge"), url(r"^checkin/([A-Z0-9]{6})/badge$", views.checken_in_badge, name="check_in_badge"),
url(r"^checkin/([A-Z0-9]{6})/barcode.png$", views.checkin_barcode_png, name="checkin_barcode_png"),
url(r"^$", views.redir_main, name="checkin_choose"), url(r"^$", views.redir_main, name="checkin_choose"),
] ]

View file

@ -58,12 +58,20 @@ def boardingpass(request):
checkin = CheckIn.objects.get_or_create(user=user)[0] checkin = CheckIn.objects.get_or_create(user=user)[0]
boardingpass = checkin.boardingpass boardingpass = checkin.boardingpass
# QR code
qrcode_url = request.build_absolute_uri(reverse("regidesk:checkin_png", args=[checkin.code])) qrcode_url = request.build_absolute_uri(reverse("regidesk:checkin_png", args=[checkin.code]))
qrcode = checkin.qrcode qrcode = checkin.qrcode
qrcode_string ='<img src="data:image/png;base64,' + qrcode + '"/>' qrcode_string ='<img src="data:image/png;base64,' + qrcode + '"/>'
not_qrcode_string = '<img src="cid:qrcode.png"/>' not_qrcode_string = '<img src="cid:qrcode.png"/>'
# Barcode
barcode = checkin.barcode
barcode_string ='<img src="data:image/png;base64,' + barcode + '"/>'
not_barcode_string = '<img src="cid:barcode.png"/>'
boardingpass_body = boardingpass.html_body.replace(not_qrcode_string, qrcode_string) boardingpass_body = boardingpass.html_body.replace(not_qrcode_string, qrcode_string)
boardingpass_body = boardingpass.html_body.replace(not_barcode_string, barcode_string)
ctx = { 'attendee': user.attendee, ctx = { 'attendee': user.attendee,
'boardingpass_body': boardingpass_body, 'boardingpass_body': boardingpass_body,
'boardingpass': boardingpass 'boardingpass': boardingpass
@ -113,6 +121,7 @@ def boarding_overview(request, boarding_state="pending"):
return render(request, "regidesk/boardingpass_overview.html", ctx) return render(request, "regidesk/boardingpass_overview.html", ctx)
def checkin_png(request, checkin_code): def checkin_png(request, checkin_code):
checkin = CheckIn.objects.get(checkin_code=checkin_code) checkin = CheckIn.objects.get(checkin_code=checkin_code)
@ -144,6 +153,22 @@ def checkin_qrcode_url(code):
return qrcode_url return qrcode_url
def checkin_barcode_png(request, checkin_code):
checkin = CheckIn.objects.get(checkin_code=checkin_code)
if not checkin:
raise Http404()
response = HttpResponse()
response["Content-Type"] = "image/png"
response["Content-Disposition"] = 'inline; filename="barcode.png"'
barcode = base64.b64decode(checkin.barcode)
response.write(barcode)
return response
@permission_required("regidesk.send_boarding_pass") @permission_required("regidesk.send_boarding_pass")
def boarding_prepare(request): def boarding_prepare(request):
@ -178,8 +203,9 @@ def boarding_prepare(request):
"user": sample_checkin.user, "user": sample_checkin.user,
"boardingpass": sample_checkin.boardingpass, "boardingpass": sample_checkin.boardingpass,
"code": sample_checkin.code, "code": sample_checkin.code,
"qrcode": '<img src="data:image/png;base64,' + sample_checkin.qrcode + '"/>', "qrcode": sample_checkin.qrcode,
"qrcode_url": checkin_qrcode_url(sample_checkin.code), "qrcode_url": checkin_qrcode_url(sample_checkin.code),
"barcode": sample_checkin.barcode,
} }
ctx = Context(sample_ctx) ctx = Context(sample_ctx)
ctx["invoices"] = invoices(ctx) ctx["invoices"] = invoices(ctx)
@ -222,6 +248,7 @@ def prepare_boarding_pass(user, template, attendee=None):
"code": user.checkin.code, "code": user.checkin.code,
"qrcode": user.checkin.qrcode, "qrcode": user.checkin.qrcode,
"qrcode_url": checkin_qrcode_url(user.checkin.code), "qrcode_url": checkin_qrcode_url(user.checkin.code),
"barcode": user.checkin.barcode,
} }
ctx = Context(ctx) ctx = Context(ctx)
ctx["invoices"] = invoices(ctx) ctx["invoices"] = invoices(ctx)
@ -264,6 +291,9 @@ def send_boarding_pass(bpass, user):
qrcode = base64.b64decode(user.checkin.qrcode) qrcode = base64.b64decode(user.checkin.qrcode)
msg.attach(filename="qrcode.png", content=qrcode, mimetype="image/png") msg.attach(filename="qrcode.png", content=qrcode, mimetype="image/png")
barcode = base64.b64decode(user.checkin.barcode)
msg.attach(filename="barcode.png", content=barcode, mimetype="image/png")
msg.send() msg.send()
bpass.sent = datetime.now() bpass.sent = datetime.now()
bpass.save() bpass.save()
@ -350,6 +380,7 @@ def checken_in_badge(request, access_code):
badge = render_badge(check_in[0].user, format="svg", overlay=True) badge = render_badge(check_in[0].user, format="svg", overlay=True)
return badge return badge
@login_required @login_required
def redir_main(request): def redir_main(request):
if request.user.has_perm('regidesk.view_boarding_pass'): if request.user.has_perm('regidesk.view_boarding_pass'):

View file

@ -2,3 +2,5 @@ django-countries>=6.1.3
requests>=2.24.0 requests>=2.24.0
pypng pypng
pyqrcode pyqrcode
python-barcode
python-barcode[images]