mirror of
https://github.com/pretix/pretix.git
synced 2026-05-05 15:14:04 +00:00
Add QR codes for pseudonymization ID
This commit is contained in:
@@ -128,7 +128,7 @@ class OrderPositionSerializer(I18nAwareModelSerializer):
|
||||
model = OrderPosition
|
||||
fields = ('id', 'order', 'positionid', 'item', 'variation', 'price', 'attendee_name', 'attendee_email',
|
||||
'voucher', 'tax_rate', 'tax_value', 'secret', 'addon_to', 'subevent', 'checkins', 'downloads',
|
||||
'answers', 'tax_rule')
|
||||
'answers', 'tax_rule', 'pseudonymization_id')
|
||||
|
||||
|
||||
class OrderFeeSerializer(I18nAwareModelSerializer):
|
||||
|
||||
45
src/pretix/base/migrations/0093_auto_20180528_1432.py
Normal file
45
src/pretix/base/migrations/0093_auto_20180528_1432.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.13 on 2018-05-28 14:32
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
from django.utils.crypto import get_random_string
|
||||
|
||||
|
||||
def set_pids(apps, schema_editor):
|
||||
OrderPosition = apps.get_model('pretixbase', 'OrderPosition') # noqa
|
||||
taken = set()
|
||||
charset = list('ABCDEFGHJKLMNPQRSTUVWXYZ3789')
|
||||
for op in OrderPosition.objects.iterator():
|
||||
while True:
|
||||
code = get_random_string(length=10, allowed_chars=charset)
|
||||
if code not in taken:
|
||||
op.pseudonymization_id = code
|
||||
taken.add(code)
|
||||
break
|
||||
op.save(update_fields=['pseudonymization_id'])
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pretixbase', '0092_auto_20180511_1224'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='orderposition',
|
||||
name='pseudonymization_id',
|
||||
field=models.CharField(db_index=True, max_length=16, null=True, unique=True),
|
||||
),
|
||||
migrations.RunPython(
|
||||
set_pids,
|
||||
migrations.RunPython.noop,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='orderposition',
|
||||
name='pseudonymization_id',
|
||||
field=models.CharField(db_index=True, default='', max_length=16, unique=True),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -835,6 +835,11 @@ class OrderPosition(AbstractPosition):
|
||||
verbose_name=_('Tax value')
|
||||
)
|
||||
secret = models.CharField(max_length=64, default=generate_position_secret, db_index=True)
|
||||
pseudonymization_id = models.CharField(
|
||||
max_length=16,
|
||||
unique=True,
|
||||
db_index=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Order position")
|
||||
@@ -916,8 +921,24 @@ class OrderPosition(AbstractPosition):
|
||||
if self.pk is None:
|
||||
while OrderPosition.objects.filter(secret=self.secret).exists():
|
||||
self.secret = generate_position_secret()
|
||||
|
||||
if not self.pseudonymization_id:
|
||||
self.assign_pseudonymization_id()
|
||||
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
def assign_pseudonymization_id(self):
|
||||
# This omits some character pairs completely because they are hard to read even on screens (1/I and O/0)
|
||||
# and includes only one of two characters for some pairs because they are sometimes hard to distinguish in
|
||||
# handwriting (2/Z, 4/A, 5/S, 6/G). This allows for better detection e.g. in incoming wire transfers that
|
||||
# might include OCR'd handwritten text
|
||||
charset = list('ABCDEFGHJKLMNPQRSTUVWXYZ3789')
|
||||
while True:
|
||||
code = get_random_string(length=10, allowed_chars=charset)
|
||||
if not OrderPosition.objects.filter(pseudonymization_id=code).exists():
|
||||
self.pseudonymization_id = code
|
||||
return
|
||||
|
||||
|
||||
class CartPosition(AbstractPosition):
|
||||
"""
|
||||
|
||||
@@ -211,8 +211,14 @@ class Renderer:
|
||||
pdfmetrics.registerFont(TTFont(family + ' B I', finders.find(styles['bolditalic']['truetype'])))
|
||||
|
||||
def _draw_barcodearea(self, canvas: Canvas, op: OrderPosition, o: dict):
|
||||
content = o.get('content', 'secret')
|
||||
if content == 'secret':
|
||||
content = op.secret
|
||||
elif content == 'pseudonymization_id':
|
||||
content = op.pseudonymization_id
|
||||
|
||||
reqs = float(o['size']) * mm
|
||||
qrw = QrCodeWidget(op.secret, barLevel='H', barHeight=reqs, barWidth=reqs)
|
||||
qrw = QrCodeWidget(content, barLevel='H', barHeight=reqs, barWidth=reqs)
|
||||
d = Drawing(reqs, reqs)
|
||||
d.add(qrw)
|
||||
qr_x = float(o['left']) * mm
|
||||
|
||||
@@ -317,9 +317,15 @@
|
||||
<span class="fa fa-font"></span>
|
||||
{% trans "Text" %}
|
||||
</button>
|
||||
<button class="btn btn-default btn-block" id="editor-add-qrcode" disabled>
|
||||
<button class="btn btn-default btn-block" id="editor-add-qrcode" data-content="secret" disabled>
|
||||
<span class="fa fa-qrcode"></span>
|
||||
{% trans "QR code area" %}
|
||||
{% trans "QR code for Check-In" %}
|
||||
</button>
|
||||
<button class="btn btn-default btn-block" id="editor-add-qrcode-lead"
|
||||
data-content="pseudonymization_id"
|
||||
disabled>
|
||||
<span class="fa fa-qrcode"></span>
|
||||
{% trans "QR code for Lead Scanning" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -18,7 +18,11 @@ fabric.Barcodearea = fabric.util.createClass(fabric.Rect, {
|
||||
|
||||
ctx.font = '16px Helvetica';
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.fillText(gettext('QR Code'), -this.width / 2, -this.height / 2 + 20);
|
||||
if (this.content === "pseudonymization_id") {
|
||||
ctx.fillText(gettext('Lead Scan QR'), -this.width / 2, -this.height / 2 + 20);
|
||||
} else {
|
||||
ctx.fillText(gettext('Check-in QR'), -this.width / 2, -this.height / 2 + 20);
|
||||
}
|
||||
},
|
||||
});
|
||||
fabric.Barcodearea.fromObject = function (object, callback, forceAsync) {
|
||||
@@ -112,7 +116,8 @@ var editor = {
|
||||
type: "barcodearea",
|
||||
left: editor._px2mm(left).toFixed(2),
|
||||
bottom: editor._px2mm(editor.pdf_viewport.height - o.height * o.scaleY - top).toFixed(2),
|
||||
size: editor._px2mm(o.height * o.scaleY).toFixed(2)
|
||||
size: editor._px2mm(o.height * o.scaleY).toFixed(2),
|
||||
content: o.content,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -122,6 +127,7 @@ var editor = {
|
||||
_add_from_data: function (d) {
|
||||
if (d.type === "barcodearea") {
|
||||
o = editor._add_qrcode();
|
||||
o.content = d.content;
|
||||
o.scaleToHeight(editor._mm2px(d.size));
|
||||
} else if (d.type === "textarea" || o.type === "text") {
|
||||
o = editor._add_text();
|
||||
@@ -418,6 +424,7 @@ var editor = {
|
||||
lockRotation: true,
|
||||
lockUniScaling: true,
|
||||
fill: '#666',
|
||||
content: $(this).attr("data-content"),
|
||||
});
|
||||
rect.setControlsVisibility({'mtr': false});
|
||||
editor.fabric.add(rect);
|
||||
@@ -645,7 +652,7 @@ var editor = {
|
||||
editor.$fcv = $("#fabric-canvas");
|
||||
editor.$cva = $("#editor-canvas-area");
|
||||
editor._load_pdf();
|
||||
$("#editor-add-qrcode").click(editor._add_qrcode);
|
||||
$("#editor-add-qrcode, #editor-add-qrcode-lead").click(editor._add_qrcode);
|
||||
$("#editor-add-text").click(editor._add_text);
|
||||
editor.$cva.get(0).tabIndex = 1000;
|
||||
editor.$cva.on("keydown", editor._on_keydown);
|
||||
|
||||
Reference in New Issue
Block a user