List and display tickets (close #6)
This commit is contained in:
parent
093f9bddf9
commit
aa3a3c0428
|
@ -59,6 +59,7 @@ TEMPLATES = [
|
|||
'django.contrib.messages.context_processors.messages',
|
||||
'camps.context_processors.current_camp',
|
||||
'shop.context_processors.current_order',
|
||||
'shop.context_processors.user_has_tickets',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
|
@ -106,6 +106,6 @@ footer {
|
|||
padding: 5px;
|
||||
}
|
||||
|
||||
.breadcrumb > li.pull-right::before {
|
||||
.breadcrumb > li.no-before::before {
|
||||
content: "";
|
||||
}
|
||||
|
|
19
news/migrations/0002_auto_20160530_2223.py
Normal file
19
news/migrations/0002_auto_20160530_2223.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.6 on 2016-05-30 22:23
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('news', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='newsitem',
|
||||
options={'ordering': ['-published_at']},
|
||||
),
|
||||
]
|
|
@ -1,3 +1,6 @@
|
|||
from django.conf import settings
|
||||
|
||||
|
||||
def current_order(request):
|
||||
if request.user.is_authenticated():
|
||||
order = None
|
||||
|
@ -10,3 +13,10 @@ def current_order(request):
|
|||
return {}
|
||||
|
||||
|
||||
def user_has_tickets(request):
|
||||
has_tickets = False
|
||||
if request.user.orders.filter(
|
||||
tickets__product__category__pk=settings.TICKET_CATEGORY_ID
|
||||
).exists():
|
||||
has_tickets = True
|
||||
return {'has_tickets': has_tickets}
|
||||
|
|
20
shop/migrations/0021_ticket_email.py
Normal file
20
shop/migrations/0021_ticket_email.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.6 on 2016-05-30 22:23
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('shop', '0020_auto_20160530_1824'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='ticket',
|
||||
name='email',
|
||||
field=models.EmailField(blank=True, max_length=254, null=True),
|
||||
),
|
||||
]
|
|
@ -288,8 +288,8 @@ class CoinifyAPICallback(CreatedUpdatedModel):
|
|||
|
||||
|
||||
class Ticket(CreatedUpdatedModel, UUIDModel):
|
||||
order = models.ForeignKey('shop.Order')
|
||||
product = models.ForeignKey('shop.Product')
|
||||
order = models.ForeignKey('shop.Order', related_name='tickets')
|
||||
product = models.ForeignKey('shop.Product', related_name='tickets')
|
||||
qrcode_base64 = models.TextField(null=True, blank=True)
|
||||
|
||||
name = models.CharField(
|
||||
|
@ -300,6 +300,11 @@ class Ticket(CreatedUpdatedModel, UUIDModel):
|
|||
),
|
||||
)
|
||||
|
||||
email = models.EmailField(
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return 'Ticket {user} {product}'.format(
|
||||
user=self.order.user,
|
||||
|
@ -321,12 +326,18 @@ class Ticket(CreatedUpdatedModel, UUIDModel):
|
|||
).hexdigest()
|
||||
|
||||
def get_qr_code(self):
|
||||
qr = qrcode.make(self.get_token())
|
||||
qr = qrcode.make(
|
||||
self.get_token(),
|
||||
version=1,
|
||||
error_correction=qrcode.constants.ERROR_CORRECT_H
|
||||
).resize((250,250))
|
||||
file_like = io.BytesIO()
|
||||
qr.save(file_like)
|
||||
qr.save(file_like, format='png')
|
||||
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)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return str(reverse_lazy('shop:ticket_detail', kwargs={'pk': self.pk}))
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-xs-12 col-md-8">
|
||||
<div class="col-sm-12 col-md-8">
|
||||
<h2>{{ product.name }}</h2>
|
||||
{{ product.description|commonmark }}
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-4">
|
||||
<div class="col-sm-12 col-md-4">
|
||||
|
||||
<h3>Add to order</h3>
|
||||
|
||||
|
|
|
@ -13,7 +13,10 @@
|
|||
<li class="active">{{ current_category }}</li>
|
||||
{% endif %}
|
||||
{% if user.is_authenticated and user.orders.exists %}
|
||||
<li class="pull-right"><a href="{% url 'shop:order_list' %}">Previous orders</a></li>
|
||||
{% if has_tickets %}
|
||||
<li class="pull-right"><a href="{% url 'shop:ticket_list' %}">Tickets</a></li>
|
||||
{% endif %}
|
||||
<li class="pull-right no-before"><a href="{% url 'shop:order_list' %}">Orders</a></li>
|
||||
{% endif %}
|
||||
</ol>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
{% extends 'shop_base.html' %}
|
||||
{% load bootstrap3 %}
|
||||
{% load shop_tags %}
|
||||
|
||||
{% block shop_content %}
|
||||
|
||||
<div class="well">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-5" style="text-align: center;">
|
||||
<h3>{{ ticket.product.name }} ticket</h3>
|
||||
<div style="margin:0px auto;width:250px;height:250px;background-image:url({{ ticket.get_qr_code_url }});"></div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-7">
|
||||
<div class="pull-right">
|
||||
<h2>{{ ticket.order.camp }}</h2>
|
||||
<form method="POST" class="form">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_field form.name %}
|
||||
{% bootstrap_field form.email %}
|
||||
<button class="btn btn-primary form-control" type="submit"><i class="glyphicon glyphicon-check"></i> Save</button>
|
||||
</form>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="pull-right">
|
||||
<a href="#" class="btn btn-default">Answer questionnaire</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -3,9 +3,38 @@
|
|||
{% load shop_tags %}
|
||||
|
||||
{% block shop_content %}
|
||||
<h3>Tickets</h3>
|
||||
|
||||
<table class="table table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Ticket owner
|
||||
<th>
|
||||
Product name
|
||||
<th>
|
||||
Price
|
||||
|
||||
<tbody>
|
||||
{% for ticket in tickets %}
|
||||
{{ ticket }}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{% url 'shop:ticket_detail' pk=ticket.pk %}" class="btn">
|
||||
{% if ticket.name %}
|
||||
{{ ticket.name }}
|
||||
{% else %}
|
||||
Click here to set the owner of this ticket
|
||||
{% endif %}
|
||||
</a>
|
||||
<td>
|
||||
<a href="{% url 'shop:ticket_detail' pk=ticket.pk %}" class="btn">
|
||||
{{ ticket.product.name }}
|
||||
<i class="glyphicon glyphicon-eye"></i>
|
||||
</a>
|
||||
<td>
|
||||
{{ ticket.product.price|currency }}
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -21,6 +21,7 @@ urlpatterns = [
|
|||
url(r'orders/(?P<pk>[0-9]+)/pay/banktransfer/$', BankTransferView.as_view(), name='bank_transfer'),
|
||||
|
||||
url(r'tickets/$', TicketListView.as_view(), name='ticket_list'),
|
||||
url(r'tickets/(?P<pk>\b[0-9A-Fa-f]{8}\b(-\b[0-9A-Fa-f]{4}\b){3}-\b[0-9A-Fa-f]{12}\b)$', TicketDetailView.as_view(), name='ticket_detail'),
|
||||
|
||||
url(r'privacy-policy/$', TemplateView.as_view(template_name='law/privacy_policy.html'), name='privacy-policy'),
|
||||
url(r'return-policy/$', TemplateView.as_view(template_name='law/return_policy.html'), name='return-policy'),
|
||||
|
|
|
@ -11,6 +11,7 @@ from django.views.generic import (
|
|||
ListView,
|
||||
DetailView,
|
||||
FormView,
|
||||
UpdateView,
|
||||
)
|
||||
from django.views.generic.base import RedirectView
|
||||
from django.views.generic.detail import SingleObjectMixin
|
||||
|
@ -486,3 +487,19 @@ class TicketListView(LoginRequiredMixin, ListView):
|
|||
user = self.request.user
|
||||
return tickets.filter(order__user=user)
|
||||
|
||||
|
||||
class TicketDetailView(LoginRequiredMixin, UpdateView, DetailView):
|
||||
model = Ticket
|
||||
template_name = 'ticket_detail.html'
|
||||
context_object_name = 'ticket'
|
||||
fields = ['name', 'email']
|
||||
|
||||
def form_valid(self, form):
|
||||
messages.info(self.request, 'Ticket updated!')
|
||||
return super(TicketDetailView, self).form_valid(form)
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
ticket = self.get_object()
|
||||
if ticket.order.user != request.user:
|
||||
return Http404
|
||||
return super(TicketDetailView, self).dispatch(request, *args, **kwargs)
|
||||
|
|
Loading…
Reference in a new issue