From d6138a7a0c7ba635c1f5393de192dde6a59f368d Mon Sep 17 00:00:00 2001 From: Skia Date: Mon, 3 Oct 2016 19:30:05 +0200 Subject: [PATCH] Make the etickets --- core/templates/core/user_account.jinja | 8 + core/views/user.py | 8 +- counter/admin.py | 1 + counter/migrations/0009_eticket.py | 23 ++ counter/migrations/0010_auto_20161003_1900.py | 24 ++ counter/models.py | 36 +++ counter/templates/counter/eticket_list.jinja | 24 ++ counter/urls.py | 4 + counter/views.py | 114 +++++++++- locale/fr/LC_MESSAGES/django.mo | Bin 36044 -> 36441 bytes locale/fr/LC_MESSAGES/django.po | 205 +++++++++++------- requirements.txt | 2 + 12 files changed, 355 insertions(+), 94 deletions(-) create mode 100644 counter/migrations/0009_eticket.py create mode 100644 counter/migrations/0010_auto_20161003_1900.py create mode 100644 counter/templates/counter/eticket_list.jinja diff --git a/core/templates/core/user_account.jinja b/core/templates/core/user_account.jinja index dfc3cdd8..3b459fc1 100644 --- a/core/templates/core/user_account.jinja +++ b/core/templates/core/user_account.jinja @@ -46,6 +46,14 @@

{% trans %}Eboutic invoices{% endtrans %}

{{ monthly(invoices_month) }} {% endif %} +{% if etickets %} +

{% trans %}Etickets{% endtrans %}

+ +{% endif %} {% else %}

{% trans %}User has no account{% endtrans %}

{% endif %} diff --git a/core/views/user.py b/core/views/user.py index 00b5179c..c5f83d1b 100644 --- a/core/views/user.py +++ b/core/views/user.py @@ -368,7 +368,6 @@ class UserAccountBase(UserTabsMixin, DetailView): """ Base class for UserAccount """ - model = User pk_url_kwarg = "user_id" current_tab = "account" @@ -386,7 +385,6 @@ class UserAccountView(UserAccountBase): """ Display a user's account """ - template_name = "core/user_account.jinja" def expense_by_month(self, obj, calc): @@ -406,7 +404,6 @@ class UserAccountView(UserAccountBase): month )) i += 1 - return stats def invoices_calc(self, query): @@ -432,18 +429,15 @@ class UserAccountView(UserAccountBase): self.object.customer.refillings, (lambda q: q.amount) ) + kwargs['etickets'] = self.object.customer.buyings.exclude(product__eticket=None).all() except: pass - # TODO: add list of month where account has activity return kwargs - - class UserAccountDetailView(UserAccountBase, YearMixin, MonthMixin): """ Display a user's account for month """ - template_name = "core/user_account_detail.jinja" def get_context_data(self, **kwargs): diff --git a/counter/admin.py b/counter/admin.py index 7361dc6f..b975ab58 100644 --- a/counter/admin.py +++ b/counter/admin.py @@ -11,4 +11,5 @@ admin.site.register(Refilling) admin.site.register(Selling) admin.site.register(Permanency) admin.site.register(CashRegisterSummary) +admin.site.register(Eticket) diff --git a/counter/migrations/0009_eticket.py b/counter/migrations/0009_eticket.py new file mode 100644 index 00000000..b59038b4 --- /dev/null +++ b/counter/migrations/0009_eticket.py @@ -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')), + ], + ), + ] diff --git a/counter/migrations/0010_auto_20161003_1900.py b/counter/migrations/0010_auto_20161003_1900.py new file mode 100644 index 00000000..9f1d73c4 --- /dev/null +++ b/counter/migrations/0010_auto_20161003_1900.py @@ -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), + ), + ] diff --git a/counter/models.py b/counter/models.py index cb6f4268..d66211e9 100644 --- a/counter/models.py +++ b/counter/models.py @@ -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() + diff --git a/counter/templates/counter/eticket_list.jinja b/counter/templates/counter/eticket_list.jinja new file mode 100644 index 00000000..6c6f0b51 --- /dev/null +++ b/counter/templates/counter/eticket_list.jinja @@ -0,0 +1,24 @@ +{% extends "core/base.jinja" %} + +{% block title %} +{% trans %}Eticket list{% endtrans %} +{% endblock %} + +{% block content %} +

{% trans %}New eticket{% endtrans %}

+{% if eticket_list %} +

{% trans %}Eticket list{% endtrans %}

+ +{% else %} +{% trans %}There is no eticket in this website.{% endtrans %} +{% endif %} +{% endblock %} + + + + + diff --git a/counter/urls.py b/counter/urls.py index 83b735df..72b53406 100644 --- a/counter/urls.py +++ b/counter/urls.py @@ -11,6 +11,7 @@ urlpatterns = [ url(r'^(?P[0-9]+)/stats$', CounterStatView.as_view(), name='stats'), url(r'^(?P[0-9]+)/login$', CounterLogin.as_view(), name='login'), url(r'^(?P[0-9]+)/logout$', CounterLogout.as_view(), name='logout'), + url(r'^eticket/(?P[0-9]+)/pdf$', EticketPDFView.as_view(), name='eticket_pdf'), url(r'^admin/(?P[0-9]+)$', CounterEditView.as_view(), name='admin'), url(r'^admin/(?P[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[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[0-9]+)$', EticketEditView.as_view(), name='edit_eticket'), url(r'^admin/selling/(?P[0-9]+)/delete$', SellingDeleteView.as_view(), name='selling_delete'), url(r'^admin/refilling/(?P[0-9]+)/delete$', RefillingDeleteView.as_view(), name='refilling_delete'), ] diff --git a/counter/views.py b/counter/views.py index 3a8bb554..ac4f2e50 100644 --- a/counter/views.py +++ b/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 + diff --git a/locale/fr/LC_MESSAGES/django.mo b/locale/fr/LC_MESSAGES/django.mo index 2900a0b5f4f6eef36c96210cd65bd0493ac751e2..3f26652ef7df4e8f20cf8b9adad8ef4c950e7e72 100644 GIT binary patch delta 13436 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\n" "Language-Team: AE info \n" @@ -17,8 +17,8 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: accounting/models.py:36 accounting/models.py:55 accounting/models.py:82 -#: accounting/models.py:132 club/models.py:19 counter/models.py:60 -#: counter/models.py:85 counter/models.py:120 launderette/models.py:15 +#: accounting/models.py:132 club/models.py:19 counter/models.py:62 +#: counter/models.py:87 counter/models.py:122 launderette/models.py:15 #: launderette/models.py:60 launderette/models.py:85 msgid "name" msgstr "nom" @@ -64,7 +64,7 @@ msgid "account number" msgstr "numero de compte" #: accounting/models.py:58 accounting/models.py:83 club/models.py:145 -#: counter/models.py:94 counter/models.py:121 +#: counter/models.py:96 counter/models.py:123 msgid "club" msgstr "club" @@ -85,12 +85,12 @@ msgstr "Compte club" msgid "%(club_account)s on %(bank_account)s" msgstr "%(club_account)s sur %(bank_account)s" -#: accounting/models.py:130 club/models.py:146 counter/models.py:336 +#: accounting/models.py:130 club/models.py:146 counter/models.py:341 #: launderette/models.py:122 msgid "start date" msgstr "date de début" -#: accounting/models.py:131 club/models.py:147 counter/models.py:337 +#: accounting/models.py:131 club/models.py:147 counter/models.py:342 msgid "end date" msgstr "date de fin" @@ -102,8 +102,8 @@ msgstr "est fermé" msgid "club account" msgstr "compte club" -#: accounting/models.py:135 accounting/models.py:178 counter/models.py:25 -#: counter/models.py:224 +#: accounting/models.py:135 accounting/models.py:178 counter/models.py:27 +#: counter/models.py:226 msgid "amount" msgstr "montant" @@ -124,16 +124,16 @@ msgid "journal" msgstr "classeur" #: accounting/models.py:179 core/models.py:479 core/models.py:757 -#: counter/models.py:227 counter/models.py:270 counter/models.py:353 +#: counter/models.py:229 counter/models.py:272 counter/models.py:358 #: eboutic/models.py:15 eboutic/models.py:48 msgid "date" msgstr "date" -#: accounting/models.py:180 counter/models.py:354 +#: accounting/models.py:180 counter/models.py:359 msgid "comment" msgstr "commentaire" -#: accounting/models.py:181 counter/models.py:228 counter/models.py:271 +#: accounting/models.py:181 counter/models.py:230 counter/models.py:273 #: subscription/models.py:57 msgid "payment method" msgstr "méthode de paiement" @@ -225,7 +225,7 @@ msgstr "" "Vous devez fournir soit un type comptable simplifié ou un type comptable " "standard" -#: accounting/models.py:277 counter/models.py:89 +#: accounting/models.py:277 counter/models.py:91 msgid "code" msgstr "code" @@ -233,7 +233,7 @@ msgstr "code" msgid "An accounting type code contains only numbers" msgstr "Un code comptable ne contient que des numéros" -#: accounting/models.py:282 accounting/models.py:308 counter/models.py:262 +#: accounting/models.py:282 accounting/models.py:308 counter/models.py:264 msgid "label" msgstr "intitulé" @@ -485,7 +485,7 @@ msgid "Done" msgstr "Effectué" #: accounting/templates/accounting/journal_details.jinja:34 -#: counter/templates/counter/cash_summary_list.jinja:32 counter/views.py:697 +#: counter/templates/counter/cash_summary_list.jinja:32 counter/views.py:702 msgid "Comment" msgstr "Commentaire" @@ -554,7 +554,7 @@ msgstr "Vous ne pouvez pas faire de boucles dans les clubs" msgid "A club with that unix_name already exists" msgstr "Un club avec ce nom UNIX existe déjà." -#: club/models.py:144 counter/models.py:334 counter/models.py:351 +#: club/models.py:144 counter/models.py:339 counter/models.py:356 #: eboutic/models.py:14 eboutic/models.py:47 launderette/models.py:89 #: launderette/models.py:126 msgid "user" @@ -564,8 +564,8 @@ msgstr "nom d'utilisateur" msgid "role" msgstr "rôle" -#: club/models.py:150 core/models.py:32 counter/models.py:61 -#: counter/models.py:86 +#: club/models.py:150 core/models.py:32 counter/models.py:63 +#: counter/models.py:88 msgid "description" msgstr "description" @@ -581,8 +581,7 @@ msgstr "L'utilisateur est déjà membre de ce club" msgid "past member" msgstr "Anciens membres" -#: club/templates/club/club_list.jinja:4 -#: club/templates/club/club_list.jinja:24 +#: club/templates/club/club_list.jinja:4 club/templates/club/club_list.jinja:24 msgid "Club list" msgstr "Liste des clubs" @@ -760,6 +759,7 @@ msgid "End date" msgstr "Date de fin" #: club/views.py:178 core/templates/core/user_stats.jinja:27 +#: counter/views.py:964 msgid "Product" msgstr "Produit" @@ -1371,13 +1371,11 @@ msgstr "login" msgid "Lost password?" msgstr "Mot de passe perdu ?" -#: core/templates/core/macros.jinja:27 -#: core/templates/core/user_detail.jinja:27 +#: core/templates/core/macros.jinja:27 core/templates/core/user_detail.jinja:27 msgid "Born: " msgstr "Né le : " -#: core/templates/core/macros.jinja:31 -#: core/templates/core/user_detail.jinja:48 +#: core/templates/core/macros.jinja:31 core/templates/core/user_detail.jinja:48 msgid "Promo: " msgstr "Promo : " @@ -1588,8 +1586,7 @@ msgstr "Résultat de la recherche" msgid "Users" msgstr "Utilisateurs" -#: core/templates/core/search.jinja:18 -#: counter/templates/counter/stats.jinja:17 +#: core/templates/core/search.jinja:18 counter/templates/counter/stats.jinja:17 msgid "Clubs" msgstr "Clubs" @@ -1629,7 +1626,11 @@ msgstr "Achat sur compte utilisateur" msgid "Eboutic invoices" msgstr "Facture eboutic" -#: core/templates/core/user_account.jinja:50 +#: core/templates/core/user_account.jinja:50 counter/views.py:470 +msgid "Etickets" +msgstr "" + +#: core/templates/core/user_account.jinja:58 #: core/templates/core/user_account_detail.jinja:103 msgid "User has no account" msgstr "L'utilisateur n'a pas de compte" @@ -1790,7 +1791,7 @@ msgid "Subscriptions" msgstr "Cotisations" #: core/templates/core/user_tools.jinja:23 counter/views.py:440 -#: counter/views.py:584 +#: counter/views.py:589 msgid "Counters" msgstr "Comptoirs" @@ -1888,83 +1889,83 @@ msgstr "Fillot" msgid "User already has a profile picture" msgstr "L'utilisateur a déjà une photo de profil" -#: counter/models.py:24 +#: counter/models.py:26 msgid "account id" msgstr "numéro de compte" -#: counter/models.py:28 +#: counter/models.py:30 msgid "customer" msgstr "client" -#: counter/models.py:29 +#: counter/models.py:31 msgid "customers" msgstr "clients" -#: counter/models.py:44 counter/templates/counter/counter_click.jinja:46 +#: counter/models.py:46 counter/templates/counter/counter_click.jinja:46 msgid "Not enough money" msgstr "Solde insuffisant" -#: counter/models.py:65 counter/models.py:87 +#: counter/models.py:67 counter/models.py:89 msgid "product type" msgstr "type du produit" -#: counter/models.py:90 +#: counter/models.py:92 msgid "purchase price" msgstr "prix d'achat" -#: counter/models.py:91 +#: counter/models.py:93 msgid "selling price" msgstr "prix de vente" -#: counter/models.py:92 +#: counter/models.py:94 msgid "special selling price" msgstr "prix de vente spécial" -#: counter/models.py:93 +#: counter/models.py:95 msgid "icon" msgstr "icône" -#: counter/models.py:95 +#: counter/models.py:97 msgid "limit age" msgstr "âge limite" -#: counter/models.py:96 +#: counter/models.py:98 msgid "tray price" msgstr "prix plateau" -#: counter/models.py:97 +#: counter/models.py:99 msgid "parent product" msgstr "produit parent" -#: counter/models.py:99 +#: counter/models.py:101 msgid "buying groups" msgstr "groupe d'achat" -#: counter/models.py:100 +#: counter/models.py:102 msgid "archived" msgstr "archivé" -#: counter/models.py:103 +#: counter/models.py:105 counter/models.py:439 msgid "product" msgstr "produit" -#: counter/models.py:122 +#: counter/models.py:124 msgid "products" msgstr "produits" -#: counter/models.py:123 +#: counter/models.py:125 msgid "counter type" msgstr "type de comptoir" -#: counter/models.py:125 +#: counter/models.py:127 msgid "Bar" msgstr "Bar" -#: counter/models.py:125 +#: counter/models.py:127 msgid "Office" msgstr "Bureau" -#: counter/models.py:125 counter/templates/counter/counter_list.jinja:11 +#: counter/models.py:127 counter/templates/counter/counter_list.jinja:11 #: eboutic/templates/eboutic/eboutic_main.jinja:4 #: eboutic/templates/eboutic/eboutic_main.jinja:24 #: eboutic/templates/eboutic/eboutic_makecommand.jinja:8 @@ -1973,84 +1974,100 @@ msgstr "Bureau" msgid "Eboutic" msgstr "Eboutic" -#: counter/models.py:126 +#: counter/models.py:128 msgid "sellers" msgstr "vendeurs" -#: counter/models.py:129 launderette/models.py:125 +#: counter/models.py:131 launderette/models.py:125 msgid "token" msgstr "jeton" -#: counter/models.py:132 counter/models.py:335 counter/models.py:352 +#: counter/models.py:134 counter/models.py:340 counter/models.py:357 #: launderette/models.py:16 msgid "counter" msgstr "comptoir" -#: counter/models.py:230 +#: counter/models.py:232 msgid "bank" msgstr "banque" -#: counter/models.py:232 counter/models.py:273 +#: counter/models.py:234 counter/models.py:275 msgid "is validated" msgstr "est validé" -#: counter/models.py:235 +#: counter/models.py:237 msgid "refilling" msgstr "rechargement" -#: counter/models.py:266 eboutic/models.py:103 +#: counter/models.py:268 eboutic/models.py:103 msgid "unit price" msgstr "prix unitaire" -#: counter/models.py:267 counter/models.py:424 eboutic/models.py:104 +#: counter/models.py:269 counter/models.py:429 eboutic/models.py:104 msgid "quantity" msgstr "quantité" -#: counter/models.py:272 +#: counter/models.py:274 msgid "Sith account" msgstr "Compte utilisateur" -#: counter/models.py:272 sith/settings.py:271 sith/settings.py:276 +#: counter/models.py:274 sith/settings.py:271 sith/settings.py:276 #: sith/settings.py:298 msgid "Credit card" msgstr "Carte bancaire" -#: counter/models.py:276 +#: counter/models.py:278 msgid "selling" msgstr "vente" -#: counter/models.py:338 +#: counter/models.py:343 msgid "last activity date" msgstr "dernière activité" -#: counter/models.py:341 +#: counter/models.py:346 msgid "permanency" msgstr "permanence" -#: counter/models.py:355 +#: counter/models.py:360 msgid "emptied" msgstr "coffre vidée" -#: counter/models.py:358 +#: counter/models.py:363 msgid "cash register summary" msgstr "relevé de caisse" -#: counter/models.py:422 +#: counter/models.py:427 msgid "cash summary" msgstr "relevé" -#: counter/models.py:423 +#: counter/models.py:428 msgid "value" msgstr "valeur" -#: counter/models.py:425 +#: counter/models.py:430 msgid "check" msgstr "chèque" -#: counter/models.py:428 +#: counter/models.py:433 msgid "cash register summary item" msgstr "élément de relevé de caisse" +#: counter/models.py:440 +msgid "banner" +msgstr "bannière" + +#: counter/models.py:441 +msgid "event date" +msgstr "date de l'événement" + +#: counter/models.py:442 +msgid "event title" +msgstr "titre de l'événement" + +#: counter/models.py:443 +msgid "secret" +msgstr "secret" + #: counter/templates/counter/activity.jinja:5 #: counter/templates/counter/activity.jinja:9 #, python-format @@ -2074,7 +2091,7 @@ msgstr "Liste des relevés de caisse" msgid "Theoric sums" msgstr "Sommes théoriques" -#: counter/templates/counter/cash_summary_list.jinja:31 counter/views.py:698 +#: counter/templates/counter/cash_summary_list.jinja:31 counter/views.py:703 msgid "Emptied" msgstr "Coffre vidé" @@ -2181,6 +2198,19 @@ msgstr "Merci de vous identifier" msgid "Barman: " msgstr "Barman : " +#: counter/templates/counter/eticket_list.jinja:4 +#: counter/templates/counter/eticket_list.jinja:10 +msgid "Eticket list" +msgstr "Liste des etickets" + +#: counter/templates/counter/eticket_list.jinja:8 +msgid "New eticket" +msgstr "Nouveau eticket" + +#: counter/templates/counter/eticket_list.jinja:17 +msgid "There is no eticket in this website." +msgstr "Il n'y a pas de eticket sur ce site web." + #: counter/templates/counter/invoices_call.jinja:4 counter/views.py:465 msgid "Invoices call" msgstr "Appels à facture" @@ -2305,61 +2335,61 @@ msgstr "Produits archivés" msgid "Product types" msgstr "Types de produit" -#: counter/views.py:581 +#: counter/views.py:586 msgid "Parent product" msgstr "Produit parent" -#: counter/views.py:582 +#: counter/views.py:587 msgid "Buying groups" msgstr "Groupes d'achat" -#: counter/views.py:677 +#: counter/views.py:682 msgid "10 cents" msgstr "10 centimes" -#: counter/views.py:678 +#: counter/views.py:683 msgid "20 cents" msgstr "20 centimes" -#: counter/views.py:679 +#: counter/views.py:684 msgid "50 cents" msgstr "50 centimes" -#: counter/views.py:680 +#: counter/views.py:685 msgid "1 euro" msgstr "1 €" -#: counter/views.py:681 +#: counter/views.py:686 msgid "2 euros" msgstr "2 €" -#: counter/views.py:682 +#: counter/views.py:687 msgid "5 euros" msgstr "5 €" -#: counter/views.py:683 +#: counter/views.py:688 msgid "10 euros" msgstr "10 €" -#: counter/views.py:684 +#: counter/views.py:689 msgid "20 euros" msgstr "20 €" -#: counter/views.py:685 +#: counter/views.py:690 msgid "50 euros" msgstr "50 €" -#: counter/views.py:686 +#: counter/views.py:691 msgid "100 euros" msgstr "100 €" -#: counter/views.py:687 counter/views.py:689 counter/views.py:691 -#: counter/views.py:693 counter/views.py:695 +#: counter/views.py:692 counter/views.py:694 counter/views.py:696 +#: counter/views.py:698 counter/views.py:700 msgid "Check amount" msgstr "Montant du chèque" -#: counter/views.py:688 counter/views.py:690 counter/views.py:692 -#: counter/views.py:694 counter/views.py:696 +#: counter/views.py:693 counter/views.py:695 counter/views.py:697 +#: counter/views.py:699 counter/views.py:701 msgid "Check quantity" msgstr "Nombre de chèque" @@ -2720,5 +2750,14 @@ msgid "You must either choose an existing user or create a new one properly" msgstr "" "Vous devez soit choisir un utilisateur existant, ou en créer un proprement." +#~ msgid "Last name" +#~ msgstr "Nom" + +#~ msgid "First name" +#~ msgstr "Prénom" + +#~ msgid "Nick name" +#~ msgstr "Surnom" + #~ msgid "Display last operations" #~ msgstr "Dernières opérations" diff --git a/requirements.txt b/requirements.txt index 04cfed6c..057a8460 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,4 +8,6 @@ pytz djangorestframework django-phonenumber-field django-ajax-selects +reportlab # mysqlclient +