diff --git a/requirements/base.txt b/requirements/base.txt index 047036d0..5940d2bb 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -5,3 +5,5 @@ django-environ>=0.4.0 psycopg2>=2.6.1 PyPDF2>=1.25.1 django-wkhtmltopdf>=3.0.0 +Pillow==3.2.0 +qrcode==5.3 \ No newline at end of file diff --git a/shop/admin.py b/shop/admin.py index dd369117..8e3054f6 100644 --- a/shop/admin.py +++ b/shop/admin.py @@ -1,18 +1,19 @@ from django.contrib import admin -from .models import Order, ProductCategory, Product, OrderProductRelation, EpayCallback, EpayPayment +from . import models -admin.site.register(EpayCallback) -admin.site.register(EpayPayment) +admin.site.register(models.EpayCallback) +admin.site.register(models.EpayPayment) -@admin.register(ProductCategory) + +@admin.register(models.ProductCategory) class ProductCategoryAdmin(admin.ModelAdmin): list_display = [ 'name', ] -@admin.register(Product) +@admin.register(models.Product) class ProductAdmin(admin.ModelAdmin): list_display = [ 'name', @@ -23,10 +24,10 @@ class ProductAdmin(admin.ModelAdmin): class ProductInline(admin.TabularInline): - model = OrderProductRelation + model = models.OrderProductRelation -@admin.register(Order) +@admin.register(models.Order) class OrderAdmin(admin.ModelAdmin): list_display = [ 'user', @@ -46,3 +47,7 @@ class OrderAdmin(admin.ModelAdmin): inlines = [ProductInline] + +@admin.register(models.Ticket) +class TicketAdmin(admin.ModelAdmin): + pass \ No newline at end of file diff --git a/shop/migrations/0012_ticket.py b/shop/migrations/0012_ticket.py new file mode 100644 index 00000000..05311de2 --- /dev/null +++ b/shop/migrations/0012_ticket.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.6 on 2016-05-23 15:08 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('shop', '0011_auto_20160517_1902'), + ] + + operations = [ + migrations.CreateModel( + name='Ticket', + fields=[ + ('created', models.DateTimeField(auto_now_add=True)), + ('updated', models.DateTimeField(auto_now=True)), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='shop.Order')), + ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='shop.Product')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/shop/migrations/0013_ticket_qrcode_base64.py b/shop/migrations/0013_ticket_qrcode_base64.py new file mode 100644 index 00000000..f9d73067 --- /dev/null +++ b/shop/migrations/0013_ticket_qrcode_base64.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.6 on 2016-05-25 16:58 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('shop', '0012_ticket'), + ] + + operations = [ + migrations.AddField( + model_name='ticket', + name='qrcode_base64', + field=models.TextField(blank=True, null=True), + ), + ] diff --git a/shop/migrations/0014_ticket_name.py b/shop/migrations/0014_ticket_name.py new file mode 100644 index 00000000..67b03d08 --- /dev/null +++ b/shop/migrations/0014_ticket_name.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.6 on 2016-05-25 17:02 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('shop', '0013_ticket_qrcode_base64'), + ] + + operations = [ + migrations.AddField( + model_name='ticket', + name='name', + field=models.CharField(default='', help_text=b'Name of the person this ticket belongs to. This can be different from the buying user.', max_length=100), + preserve_default=False, + ), + ] diff --git a/shop/models.py b/shop/models.py index b47988a7..53daf494 100644 --- a/shop/models.py +++ b/shop/models.py @@ -1,3 +1,4 @@ +from django.conf import settings from django.db import models from django.db.models.aggregates import Sum from django.contrib.postgres.fields import DateTimeRangeField, JSONField @@ -8,6 +9,12 @@ from django.core.urlresolvers import reverse_lazy from bornhack.utils import CreatedUpdatedModel, UUIDModel from .managers import ProductQuerySet +import hashlib +import io +import base64 + +import qrcode + class Order(CreatedUpdatedModel): @@ -207,3 +214,47 @@ class Invoice(CreatedUpdatedModel): self.sent_to_customer, ) + +class Ticket(CreatedUpdatedModel, UUIDModel): + order = models.ForeignKey('shop.Order') + product = models.ForeignKey('shop.Product') + qrcode_base64 = models.TextField(null=True, blank=True) + + name = models.CharField( + max_length=100, + help_text=( + 'Name of the person this ticket belongs to. ' + 'This can be different from the buying user.' + ), + ) + + def __str__(self): + return 'Ticket {user} {product}'.format( + user=self.order.user, + product=self.product + ) + + def save(self, **kwargs): + super(Ticket, self).save(**kwargs) + self.qrcode_base64 = self.get_qr_code() + super(Ticket, self).save(**kwargs) + + def get_token(self): + return hashlib.sha256( + '{ticket_id}{user_id}{secret_key}'.format( + ticket_id=self.pk, + user_id=self.order.user.pk, + secret_key=settings.SECRET_KEY, + ) + ).hexdigest() + + def get_qr_code(self): + qr = qrcode.make(self.get_token()) + file_like = io.BytesIO() + qr.save(file_like) + qrcode_base64 = base64.b64encode(file_like.getvalue()) + return qrcode_base64 + + def get_qr_code_url(self): + return 'data:image/png;base64,{}'.format(self.qrcode_base64) +