bornhack-website/src/tickets/models.py

183 lines
5.1 KiB
Python
Raw Normal View History

2017-08-17 15:51:24 +00:00
import base64
import hashlib
import io
import logging
2017-08-17 15:51:24 +00:00
import qrcode
from django.conf import settings
from django.db import models
2018-04-03 16:44:10 +00:00
from django.urls import reverse_lazy
2017-08-17 15:51:24 +00:00
from django.utils.translation import ugettext_lazy as _
from utils.models import CampRelatedModel, UUIDModel
from utils.pdf import generate_pdf_letter
2019-06-16 12:32:24 +00:00
2017-08-17 15:51:24 +00:00
logger = logging.getLogger("bornhack.%s" % __name__)
class TicketTypeManager(models.Manager):
def with_price_stats(self):
2021-07-22 05:55:58 +00:00
return self.annotate(shopticket_count=models.Count("shopticket")).exclude(
shopticket_count=0
)
# TicketType can be full week, one day, cabins, parking, merch, hax, massage, etc.
2017-08-19 23:05:30 +00:00
class TicketType(CampRelatedModel, UUIDModel):
objects = TicketTypeManager()
2017-08-17 15:51:24 +00:00
name = models.TextField()
2019-06-16 12:32:24 +00:00
camp = models.ForeignKey("camps.Camp", on_delete=models.PROTECT)
includes_badge = models.BooleanField(default=False)
single_ticket_per_product = models.BooleanField(
default=False,
help_text=(
"Only create one ticket for a product/order pair no matter the quantity. "
"Useful for products which are bought in larger quantity (ie. village chairs)"
),
)
2017-08-17 15:51:24 +00:00
def __str__(self):
2019-06-16 12:32:24 +00:00
return "{} ({})".format(self.name, self.camp.title)
2017-08-17 15:51:24 +00:00
def create_ticket_token(string):
return hashlib.sha256(string).hexdigest()
def qr_code_base64(token):
qr = qrcode.make(
token, version=1, error_correction=qrcode.constants.ERROR_CORRECT_H
).resize((250, 250))
file_like = io.BytesIO()
qr.save(file_like, format="png")
qrcode_base64 = base64.b64encode(file_like.getvalue())
return qrcode_base64
class BaseTicket(CampRelatedModel, UUIDModel):
2019-06-16 12:32:24 +00:00
ticket_type = models.ForeignKey("TicketType", on_delete=models.PROTECT)
used = models.BooleanField(default=False)
badge_handed_out = models.BooleanField(default=False)
token = models.CharField(max_length=64, blank=True)
badge_token = models.CharField(max_length=64, blank=True)
class Meta:
abstract = True
2017-08-17 15:51:24 +00:00
2020-02-07 17:46:34 +00:00
camp_filter = "ticket_type__camp"
2019-08-11 11:18:19 +00:00
@property
def camp(self):
return self.ticket_type.camp
2019-07-17 20:02:47 +00:00
def save(self, **kwargs):
self.token = self._get_token()
self.badge_token = self._get_badge_token()
2019-07-17 20:02:47 +00:00
super().save(**kwargs)
2017-08-17 15:51:24 +00:00
def _get_token(self):
return create_ticket_token(
2019-06-16 12:32:24 +00:00
"{_id}{secret_key}".format(
2019-07-17 20:02:47 +00:00
_id=self.uuid, secret_key=settings.SECRET_KEY
2019-06-16 12:32:24 +00:00
).encode("utf-8")
)
def _get_badge_token(self):
return create_ticket_token(
"{_id}{secret_key}-badge".format(
_id=self.uuid, secret_key=settings.SECRET_KEY
).encode("utf-8")
)
2017-08-17 15:51:24 +00:00
def get_qr_code_url(self):
2019-06-16 12:32:24 +00:00
return "data:image/png;base64,{}".format(
qr_code_base64(self._get_token()).decode("utf-8")
)
def get_qr_badge_code_url(self):
return "data:image/png;base64,{}".format(
qr_code_base64(self._get_badge_token()).decode("utf-8")
2018-01-07 18:59:53 +00:00
)
2017-08-17 15:51:24 +00:00
def generate_pdf(self):
formatdict = {"ticket": self}
if self.ticket_type.single_ticket_per_product and self.shortname == "shop":
formatdict["quantity"] = self.opr.quantity
return generate_pdf_letter(
2019-06-16 12:32:24 +00:00
filename="{}_ticket_{}.pdf".format(self.shortname, self.pk),
formatdict=formatdict,
2019-06-16 12:32:24 +00:00
template="pdf/ticket.html",
2017-08-17 15:51:24 +00:00
)
class SponsorTicket(BaseTicket):
2019-06-16 12:32:24 +00:00
sponsor = models.ForeignKey("sponsors.Sponsor", on_delete=models.PROTECT)
2017-08-17 15:51:24 +00:00
def __str__(self):
2019-06-16 12:32:24 +00:00
return "SponsorTicket: {}".format(self.pk)
2017-08-17 15:51:24 +00:00
2017-08-19 22:25:48 +00:00
@property
def shortname(self):
return "sponsor"
2017-08-17 15:51:24 +00:00
class DiscountTicket(BaseTicket):
2017-08-17 15:51:24 +00:00
price = models.IntegerField(
2019-06-16 12:32:24 +00:00
help_text=_("Price of the discounted ticket (in DKK, including VAT).")
2017-08-17 15:51:24 +00:00
)
def __str__(self):
2019-06-16 12:32:24 +00:00
return "DiscountTicket: {}".format(self.pk)
2017-08-17 15:51:24 +00:00
2017-08-19 22:25:48 +00:00
@property
def shortname(self):
return "discount"
2017-08-17 15:51:24 +00:00
class ShopTicket(BaseTicket):
opr = models.ForeignKey(
"shop.OrderProductRelation",
related_name="shoptickets",
on_delete=models.PROTECT,
2018-03-04 15:26:35 +00:00
)
2019-06-16 12:32:24 +00:00
product = models.ForeignKey("shop.Product", on_delete=models.PROTECT)
2017-08-17 15:51:24 +00:00
name = models.CharField(
max_length=100,
help_text=(
2019-06-16 12:32:24 +00:00
"Name of the person this ticket belongs to. "
"This can be different from the buying user."
2017-08-17 15:51:24 +00:00
),
null=True,
blank=True,
)
2019-06-16 12:32:24 +00:00
email = models.EmailField(null=True, blank=True)
2017-08-17 15:51:24 +00:00
# overwrite the _get_token method because old tickets use the user_id
def _get_token(self):
return hashlib.sha256(
2019-06-16 12:32:24 +00:00
"{_id}{user_id}{secret_key}".format(
_id=self.pk, user_id=self.order.user.pk, secret_key=settings.SECRET_KEY
).encode("utf-8")
2017-08-17 15:51:24 +00:00
).hexdigest()
def __str__(self):
2019-06-16 12:32:24 +00:00
return "Ticket {user} {product}".format(
user=self.order.user, product=self.product
2017-08-17 15:51:24 +00:00
)
def get_absolute_url(self):
2019-06-16 12:32:24 +00:00
return str(reverse_lazy("tickets:shopticket_edit", kwargs={"pk": self.pk}))
2017-08-19 22:25:48 +00:00
@property
def shortname(self):
return "shop"
@property
def order(self):
return self.opr.order