mirror of
https://github.com/ae-utbm/sith.git
synced 2025-07-10 03:49:24 +00:00
Make the etickets
This commit is contained in:
@ -11,4 +11,5 @@ admin.site.register(Refilling)
|
||||
admin.site.register(Selling)
|
||||
admin.site.register(Permanency)
|
||||
admin.site.register(CashRegisterSummary)
|
||||
admin.site.register(Eticket)
|
||||
|
||||
|
23
counter/migrations/0009_eticket.py
Normal file
23
counter/migrations/0009_eticket.py
Normal file
@ -0,0 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('counter', '0008_counter_token'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Eticket',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)),
|
||||
('banner', models.ImageField(null=True, upload_to='etickets', blank=True)),
|
||||
('secret', models.CharField(unique=True, verbose_name='secret', max_length=64)),
|
||||
('product', models.OneToOneField(verbose_name='product', related_name='eticket', to='counter.Product')),
|
||||
],
|
||||
),
|
||||
]
|
24
counter/migrations/0010_auto_20161003_1900.py
Normal file
24
counter/migrations/0010_auto_20161003_1900.py
Normal file
@ -0,0 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('counter', '0009_eticket'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='eticket',
|
||||
name='event_date',
|
||||
field=models.DateField(blank=True, verbose_name='event date', null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='eticket',
|
||||
name='event_title',
|
||||
field=models.CharField(blank=True, max_length=64, verbose_name='event title', null=True),
|
||||
),
|
||||
]
|
@ -8,6 +8,8 @@ from django.forms import ValidationError
|
||||
from datetime import timedelta
|
||||
import random
|
||||
import string
|
||||
import os
|
||||
import base64
|
||||
|
||||
from club.models import Club
|
||||
from accounting.models import CurrencyField
|
||||
@ -282,6 +284,9 @@ class Selling(models.Model):
|
||||
def is_owned_by(self, user):
|
||||
return user.is_owner(self.counter) and self.payment_method != "CARD"
|
||||
|
||||
def can_be_viewed_by(self, user):
|
||||
return user == self.customer.user
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
self.customer.amount += self.quantity * self.unit_price
|
||||
self.customer.save()
|
||||
@ -427,3 +432,34 @@ class CashRegisterSummaryItem(models.Model):
|
||||
class Meta:
|
||||
verbose_name = _("cash register summary item")
|
||||
|
||||
class Eticket(models.Model):
|
||||
"""
|
||||
Eticket can be linked to a product an allows PDF generation
|
||||
"""
|
||||
product = models.OneToOneField(Product, related_name='eticket', verbose_name=_("product"))
|
||||
banner = models.ImageField(upload_to='etickets', null=True, blank=True, verbose_name=_("banner"))
|
||||
event_date = models.DateField(_('event date'), null=True, blank=True)
|
||||
event_title = models.CharField(_('event title'), max_length=64, null=True, blank=True)
|
||||
secret = models.CharField(_('secret'), max_length=64, unique=True)
|
||||
|
||||
def __str__(self):
|
||||
return "%s" % (self.product.name)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('counter:eticket_list')
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.id:
|
||||
self.secret = base64.b64encode(os.urandom(32))
|
||||
return super(Eticket, self).save(*args, **kwargs)
|
||||
|
||||
def is_owned_by(self, user):
|
||||
"""
|
||||
Method to see if that object can be edited by the given user
|
||||
"""
|
||||
return user.is_in_group(settings.SITH_GROUPS['counter-admin']['name'])
|
||||
|
||||
def get_hash(self, string):
|
||||
import hashlib, hmac
|
||||
return hmac.new(bytes(self.secret, 'utf-8'), bytes(string, 'utf-8'), hashlib.sha1).hexdigest()
|
||||
|
||||
|
24
counter/templates/counter/eticket_list.jinja
Normal file
24
counter/templates/counter/eticket_list.jinja
Normal file
@ -0,0 +1,24 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Eticket list{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p><a href="{{ url('counter:new_eticket') }}">{% trans %}New eticket{% endtrans %}</a></p>
|
||||
{% if eticket_list %}
|
||||
<h3>{% trans %}Eticket list{% endtrans %}</h3>
|
||||
<ul>
|
||||
{% for t in eticket_list %}
|
||||
<li><a href="{{ url('counter:edit_eticket', eticket_id=t.id) }}">{{ t }} - {{ t.secret }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
{% trans %}There is no eticket in this website.{% endtrans %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -11,6 +11,7 @@ urlpatterns = [
|
||||
url(r'^(?P<counter_id>[0-9]+)/stats$', CounterStatView.as_view(), name='stats'),
|
||||
url(r'^(?P<counter_id>[0-9]+)/login$', CounterLogin.as_view(), name='login'),
|
||||
url(r'^(?P<counter_id>[0-9]+)/logout$', CounterLogout.as_view(), name='logout'),
|
||||
url(r'^eticket/(?P<selling_id>[0-9]+)/pdf$', EticketPDFView.as_view(), name='eticket_pdf'),
|
||||
url(r'^admin/(?P<counter_id>[0-9]+)$', CounterEditView.as_view(), name='admin'),
|
||||
url(r'^admin/(?P<counter_id>[0-9]+)/prop$', CounterEditPropView.as_view(), name='prop_admin'),
|
||||
url(r'^admin$', CounterListView.as_view(), name='admin_list'),
|
||||
@ -26,6 +27,9 @@ urlpatterns = [
|
||||
url(r'^admin/producttype/list$', ProductTypeListView.as_view(), name='producttype_list'),
|
||||
url(r'^admin/producttype/create$', ProductTypeCreateView.as_view(), name='new_producttype'),
|
||||
url(r'^admin/producttype/(?P<type_id>[0-9]+)$', ProductTypeEditView.as_view(), name='producttype_edit'),
|
||||
url(r'^admin/eticket/list$', EticketListView.as_view(), name='eticket_list'),
|
||||
url(r'^admin/eticket/new$', EticketCreateView.as_view(), name='new_eticket'),
|
||||
url(r'^admin/eticket/(?P<eticket_id>[0-9]+)$', EticketEditView.as_view(), name='edit_eticket'),
|
||||
url(r'^admin/selling/(?P<selling_id>[0-9]+)/delete$', SellingDeleteView.as_view(), name='selling_delete'),
|
||||
url(r'^admin/refilling/(?P<refilling_id>[0-9]+)/delete$', RefillingDeleteView.as_view(), name='refilling_delete'),
|
||||
]
|
||||
|
114
counter/views.py
114
counter/views.py
@ -6,7 +6,7 @@ from django.forms.models import modelform_factory
|
||||
from django.forms import CheckboxSelectMultiple
|
||||
from django.core.urlresolvers import reverse_lazy, reverse
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.http import HttpResponseRedirect, HttpResponse
|
||||
from django.utils import timezone
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
@ -20,11 +20,11 @@ from ajax_select.fields import AutoCompleteSelectField, AutoCompleteSelectMultip
|
||||
from ajax_select import make_ajax_form, make_ajax_field
|
||||
|
||||
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin, TabedViewMixin
|
||||
from core.views.forms import SelectUser, LoginForm
|
||||
from core.views.forms import SelectUser, LoginForm, SelectDate
|
||||
from core.models import User
|
||||
from subscription.models import Subscriber, Subscription
|
||||
from subscription.views import get_subscriber
|
||||
from counter.models import Counter, Customer, Product, Selling, Refilling, ProductType, CashRegisterSummary, CashRegisterSummaryItem
|
||||
from counter.models import Counter, Customer, Product, Selling, Refilling, ProductType, CashRegisterSummary, CashRegisterSummaryItem, Eticket
|
||||
from accounting.models import CurrencyField
|
||||
|
||||
class GetUserForm(forms.Form):
|
||||
@ -464,6 +464,11 @@ class CounterAdminTabsMixin(TabedViewMixin):
|
||||
'slug': 'invoices_call',
|
||||
'name': _("Invoices call"),
|
||||
},
|
||||
{
|
||||
'url': reverse_lazy('counter:eticket_list'),
|
||||
'slug': 'etickets',
|
||||
'name': _("Etickets"),
|
||||
},
|
||||
]
|
||||
|
||||
class CounterListView(CounterAdminTabsMixin, CanViewMixin, ListView):
|
||||
@ -940,4 +945,105 @@ class InvoiceCallView(CounterAdminTabsMixin, TemplateView):
|
||||
)).exclude(selling_sum=None).order_by('-selling_sum')
|
||||
return kwargs
|
||||
|
||||
#).exclude(selling_sum=None).order_by('-selling_sum').all()[:100]
|
||||
class EticketListView(CounterAdminTabsMixin, CanEditPropMixin, ListView):
|
||||
"""
|
||||
A list view for the admins
|
||||
"""
|
||||
model = Eticket
|
||||
template_name = 'counter/eticket_list.jinja'
|
||||
ordering = ['id']
|
||||
current_tab = "etickets"
|
||||
|
||||
class EticketForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Eticket
|
||||
fields = ['product', 'banner', 'event_title', 'event_date']
|
||||
widgets = {
|
||||
'event_date': SelectDate,
|
||||
}
|
||||
product = AutoCompleteSelectField('products', show_help_text=False, label=_("Product"), required=True)
|
||||
|
||||
class EticketCreateView(CounterAdminTabsMixin, CanEditPropMixin, CreateView):
|
||||
"""
|
||||
Create an eticket
|
||||
"""
|
||||
model = Eticket
|
||||
template_name = 'core/create.jinja'
|
||||
form_class = EticketForm
|
||||
current_tab = "etickets"
|
||||
|
||||
class EticketEditView(CounterAdminTabsMixin, CanEditPropMixin, UpdateView):
|
||||
"""
|
||||
Edit an eticket
|
||||
"""
|
||||
model = Eticket
|
||||
template_name = 'core/edit.jinja'
|
||||
form_class = EticketForm
|
||||
pk_url_kwarg = "eticket_id"
|
||||
current_tab = "etickets"
|
||||
|
||||
class EticketPDFView(CanViewMixin, DetailView):
|
||||
"""
|
||||
Display the PDF of an eticket
|
||||
"""
|
||||
model = Selling
|
||||
pk_url_kwarg = "selling_id"
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
from reportlab.pdfgen import canvas
|
||||
from reportlab.lib.utils import ImageReader
|
||||
from reportlab.lib.units import cm
|
||||
from reportlab.graphics.shapes import Drawing
|
||||
from reportlab.graphics.barcode.qr import QrCodeWidget
|
||||
from reportlab.graphics import renderPDF
|
||||
self.object = self.get_object()
|
||||
eticket = self.object.product.eticket
|
||||
user = self.object.customer.user
|
||||
code = "%s %s %s" % (self.object.customer.user.id, self.object.quantity, self.object.product.id)
|
||||
code += " " + eticket.get_hash(code)[:8].upper()
|
||||
response = HttpResponse(content_type='application/pdf')
|
||||
response['Content-Disposition'] = 'filename="eticket.pdf"'
|
||||
p = canvas.Canvas(response)
|
||||
p.setTitle("Eticket")
|
||||
im = ImageReader("core/static/core/img/eticket.jpg")
|
||||
width, height = im.getSize()
|
||||
size = max(width, height)
|
||||
width = 8 * cm * width / size
|
||||
height = 8 * cm * height / size
|
||||
p.drawImage(im, 10 * cm, 25 * cm, width, height)
|
||||
if eticket.banner:
|
||||
im = ImageReader(eticket.banner)
|
||||
width, height = im.getSize()
|
||||
size = max(width, height)
|
||||
width = 6 * cm * width / size
|
||||
height = 6 * cm * height / size
|
||||
p.drawImage(im, 1 * cm, 25 * cm, width, height)
|
||||
if user.profile_pict:
|
||||
im = ImageReader(user.profile_pict.file)
|
||||
width, height = im.getSize()
|
||||
size = max(width, height)
|
||||
width = 150 * width / size
|
||||
height = 150 * height / size
|
||||
p.drawImage(im, 10.5 * cm - width / 2, 16 * cm, width, height)
|
||||
if eticket.event_title:
|
||||
p.setFont("Helvetica-Bold", 20)
|
||||
p.drawCentredString(10.5 * cm, 23.6 * cm, eticket.event_title)
|
||||
if eticket.event_date:
|
||||
p.setFont("Helvetica-Bold", 16)
|
||||
p.drawCentredString(10.5 * cm, 22.6 * cm, eticket.event_date.strftime("%d %b %Y"))
|
||||
p.setFont("Helvetica-Bold", 14)
|
||||
p.drawCentredString(10.5 * cm, 15 * cm, user.get_display_name())
|
||||
p.setFont("Courier-Bold", 14)
|
||||
qrcode = QrCodeWidget(code)
|
||||
bounds = qrcode.getBounds()
|
||||
width = bounds[2] - bounds[0]
|
||||
height = bounds[3] - bounds[1]
|
||||
d = Drawing(260, 260, transform=[260./width, 0, 0, 260./height, 0, 0])
|
||||
d.add(qrcode)
|
||||
renderPDF.draw(d, p, 10.5 * cm - 130, 6.1 * cm)
|
||||
p.drawCentredString(10.5 * cm, 6 * cm, code)
|
||||
|
||||
p.showPage()
|
||||
p.save()
|
||||
return response
|
||||
|
||||
|
Reference in New Issue
Block a user