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 2900a0b5..3f26652e 100644 Binary files a/locale/fr/LC_MESSAGES/django.mo and b/locale/fr/LC_MESSAGES/django.mo differ diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 3efd0de9..d289f5c0 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-09-29 18:31+0200\n" +"POT-Creation-Date: 2016-10-03 19:24+0200\n" "PO-Revision-Date: 2016-07-18\n" "Last-Translator: Skia \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 +