Make the etickets

This commit is contained in:
Skia 2016-10-03 19:30:05 +02:00
parent a12f9dd53e
commit d6138a7a0c
12 changed files with 355 additions and 94 deletions

View File

@ -46,6 +46,14 @@
<h4>{% trans %}Eboutic invoices{% endtrans %}</h4> <h4>{% trans %}Eboutic invoices{% endtrans %}</h4>
{{ monthly(invoices_month) }} {{ monthly(invoices_month) }}
{% endif %} {% endif %}
{% if etickets %}
<h4>{% trans %}Etickets{% endtrans %}</h4>
<ul>
{% for s in etickets %}
<li><a href="{{ url('counter:eticket_pdf', selling_id=s.id) }}">{{ s.quantity }} x {{ s.product.eticket }}</a></li>
{% endfor %}
</ul>
{% endif %}
{% else %} {% else %}
<p>{% trans %}User has no account{% endtrans %}</p> <p>{% trans %}User has no account{% endtrans %}</p>
{% endif %} {% endif %}

View File

@ -368,7 +368,6 @@ class UserAccountBase(UserTabsMixin, DetailView):
""" """
Base class for UserAccount Base class for UserAccount
""" """
model = User model = User
pk_url_kwarg = "user_id" pk_url_kwarg = "user_id"
current_tab = "account" current_tab = "account"
@ -386,7 +385,6 @@ class UserAccountView(UserAccountBase):
""" """
Display a user's account Display a user's account
""" """
template_name = "core/user_account.jinja" template_name = "core/user_account.jinja"
def expense_by_month(self, obj, calc): def expense_by_month(self, obj, calc):
@ -406,7 +404,6 @@ class UserAccountView(UserAccountBase):
month month
)) ))
i += 1 i += 1
return stats return stats
def invoices_calc(self, query): def invoices_calc(self, query):
@ -432,18 +429,15 @@ class UserAccountView(UserAccountBase):
self.object.customer.refillings, self.object.customer.refillings,
(lambda q: q.amount) (lambda q: q.amount)
) )
kwargs['etickets'] = self.object.customer.buyings.exclude(product__eticket=None).all()
except: except:
pass pass
# TODO: add list of month where account has activity
return kwargs return kwargs
class UserAccountDetailView(UserAccountBase, YearMixin, MonthMixin): class UserAccountDetailView(UserAccountBase, YearMixin, MonthMixin):
""" """
Display a user's account for month Display a user's account for month
""" """
template_name = "core/user_account_detail.jinja" template_name = "core/user_account_detail.jinja"
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):

View File

@ -11,4 +11,5 @@ admin.site.register(Refilling)
admin.site.register(Selling) admin.site.register(Selling)
admin.site.register(Permanency) admin.site.register(Permanency)
admin.site.register(CashRegisterSummary) admin.site.register(CashRegisterSummary)
admin.site.register(Eticket)

View 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')),
],
),
]

View 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),
),
]

View File

@ -8,6 +8,8 @@ from django.forms import ValidationError
from datetime import timedelta from datetime import timedelta
import random import random
import string import string
import os
import base64
from club.models import Club from club.models import Club
from accounting.models import CurrencyField from accounting.models import CurrencyField
@ -282,6 +284,9 @@ class Selling(models.Model):
def is_owned_by(self, user): def is_owned_by(self, user):
return user.is_owner(self.counter) and self.payment_method != "CARD" 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): def delete(self, *args, **kwargs):
self.customer.amount += self.quantity * self.unit_price self.customer.amount += self.quantity * self.unit_price
self.customer.save() self.customer.save()
@ -427,3 +432,34 @@ class CashRegisterSummaryItem(models.Model):
class Meta: class Meta:
verbose_name = _("cash register summary item") 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()

View 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 %}

View File

@ -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]+)/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]+)/login$', CounterLogin.as_view(), name='login'),
url(r'^(?P<counter_id>[0-9]+)/logout$', CounterLogout.as_view(), name='logout'), 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]+)$', CounterEditView.as_view(), name='admin'),
url(r'^admin/(?P<counter_id>[0-9]+)/prop$', CounterEditPropView.as_view(), name='prop_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'), 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/list$', ProductTypeListView.as_view(), name='producttype_list'),
url(r'^admin/producttype/create$', ProductTypeCreateView.as_view(), name='new_producttype'), 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/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/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'), url(r'^admin/refilling/(?P<refilling_id>[0-9]+)/delete$', RefillingDeleteView.as_view(), name='refilling_delete'),
] ]

View File

@ -6,7 +6,7 @@ from django.forms.models import modelform_factory
from django.forms import CheckboxSelectMultiple from django.forms import CheckboxSelectMultiple
from django.core.urlresolvers import reverse_lazy, reverse from django.core.urlresolvers import reverse_lazy, reverse
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect, HttpResponse
from django.utils import timezone from django.utils import timezone
from django import forms from django import forms
from django.utils.translation import ugettext_lazy as _ 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 ajax_select import make_ajax_form, make_ajax_field
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin, TabedViewMixin 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 core.models import User
from subscription.models import Subscriber, Subscription from subscription.models import Subscriber, Subscription
from subscription.views import get_subscriber 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 from accounting.models import CurrencyField
class GetUserForm(forms.Form): class GetUserForm(forms.Form):
@ -464,6 +464,11 @@ class CounterAdminTabsMixin(TabedViewMixin):
'slug': 'invoices_call', 'slug': 'invoices_call',
'name': _("Invoices call"), 'name': _("Invoices call"),
}, },
{
'url': reverse_lazy('counter:eticket_list'),
'slug': 'etickets',
'name': _("Etickets"),
},
] ]
class CounterListView(CounterAdminTabsMixin, CanViewMixin, ListView): class CounterListView(CounterAdminTabsMixin, CanViewMixin, ListView):
@ -940,4 +945,105 @@ class InvoiceCallView(CounterAdminTabsMixin, TemplateView):
)).exclude(selling_sum=None).order_by('-selling_sum') )).exclude(selling_sum=None).order_by('-selling_sum')
return kwargs 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

Binary file not shown.

View File

@ -6,7 +6,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "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" "PO-Revision-Date: 2016-07-18\n"
"Last-Translator: Skia <skia@libskia.so>\n" "Last-Translator: Skia <skia@libskia.so>\n"
"Language-Team: AE info <ae.info@utbm.fr>\n" "Language-Team: AE info <ae.info@utbm.fr>\n"
@ -17,8 +17,8 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n > 1);\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: accounting/models.py:36 accounting/models.py:55 accounting/models.py:82 #: accounting/models.py:36 accounting/models.py:55 accounting/models.py:82
#: accounting/models.py:132 club/models.py:19 counter/models.py:60 #: accounting/models.py:132 club/models.py:19 counter/models.py:62
#: counter/models.py:85 counter/models.py:120 launderette/models.py:15 #: counter/models.py:87 counter/models.py:122 launderette/models.py:15
#: launderette/models.py:60 launderette/models.py:85 #: launderette/models.py:60 launderette/models.py:85
msgid "name" msgid "name"
msgstr "nom" msgstr "nom"
@ -64,7 +64,7 @@ msgid "account number"
msgstr "numero de compte" msgstr "numero de compte"
#: accounting/models.py:58 accounting/models.py:83 club/models.py:145 #: 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" msgid "club"
msgstr "club" msgstr "club"
@ -85,12 +85,12 @@ msgstr "Compte club"
msgid "%(club_account)s on %(bank_account)s" msgid "%(club_account)s on %(bank_account)s"
msgstr "%(club_account)s sur %(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 #: launderette/models.py:122
msgid "start date" msgid "start date"
msgstr "date de début" 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" msgid "end date"
msgstr "date de fin" msgstr "date de fin"
@ -102,8 +102,8 @@ msgstr "est fermé"
msgid "club account" msgid "club account"
msgstr "compte club" msgstr "compte club"
#: accounting/models.py:135 accounting/models.py:178 counter/models.py:25 #: accounting/models.py:135 accounting/models.py:178 counter/models.py:27
#: counter/models.py:224 #: counter/models.py:226
msgid "amount" msgid "amount"
msgstr "montant" msgstr "montant"
@ -124,16 +124,16 @@ msgid "journal"
msgstr "classeur" msgstr "classeur"
#: accounting/models.py:179 core/models.py:479 core/models.py:757 #: 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 #: eboutic/models.py:15 eboutic/models.py:48
msgid "date" msgid "date"
msgstr "date" msgstr "date"
#: accounting/models.py:180 counter/models.py:354 #: accounting/models.py:180 counter/models.py:359
msgid "comment" msgid "comment"
msgstr "commentaire" 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 #: subscription/models.py:57
msgid "payment method" msgid "payment method"
msgstr "méthode de paiement" msgstr "méthode de paiement"
@ -225,7 +225,7 @@ msgstr ""
"Vous devez fournir soit un type comptable simplifié ou un type comptable " "Vous devez fournir soit un type comptable simplifié ou un type comptable "
"standard" "standard"
#: accounting/models.py:277 counter/models.py:89 #: accounting/models.py:277 counter/models.py:91
msgid "code" msgid "code"
msgstr "code" msgstr "code"
@ -233,7 +233,7 @@ msgstr "code"
msgid "An accounting type code contains only numbers" msgid "An accounting type code contains only numbers"
msgstr "Un code comptable ne contient que des numéros" 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" msgid "label"
msgstr "intitulé" msgstr "intitulé"
@ -485,7 +485,7 @@ msgid "Done"
msgstr "Effectué" msgstr "Effectué"
#: accounting/templates/accounting/journal_details.jinja:34 #: 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" msgid "Comment"
msgstr "Commentaire" 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" msgid "A club with that unix_name already exists"
msgstr "Un club avec ce nom UNIX existe déjà." 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 #: eboutic/models.py:14 eboutic/models.py:47 launderette/models.py:89
#: launderette/models.py:126 #: launderette/models.py:126
msgid "user" msgid "user"
@ -564,8 +564,8 @@ msgstr "nom d'utilisateur"
msgid "role" msgid "role"
msgstr "rôle" msgstr "rôle"
#: club/models.py:150 core/models.py:32 counter/models.py:61 #: club/models.py:150 core/models.py:32 counter/models.py:63
#: counter/models.py:86 #: counter/models.py:88
msgid "description" msgid "description"
msgstr "description" msgstr "description"
@ -581,8 +581,7 @@ msgstr "L'utilisateur est déjà membre de ce club"
msgid "past member" msgid "past member"
msgstr "Anciens membres" msgstr "Anciens membres"
#: club/templates/club/club_list.jinja:4 #: club/templates/club/club_list.jinja:4 club/templates/club/club_list.jinja:24
#: club/templates/club/club_list.jinja:24
msgid "Club list" msgid "Club list"
msgstr "Liste des clubs" msgstr "Liste des clubs"
@ -760,6 +759,7 @@ msgid "End date"
msgstr "Date de fin" msgstr "Date de fin"
#: club/views.py:178 core/templates/core/user_stats.jinja:27 #: club/views.py:178 core/templates/core/user_stats.jinja:27
#: counter/views.py:964
msgid "Product" msgid "Product"
msgstr "Produit" msgstr "Produit"
@ -1371,13 +1371,11 @@ msgstr "login"
msgid "Lost password?" msgid "Lost password?"
msgstr "Mot de passe perdu ?" msgstr "Mot de passe perdu ?"
#: core/templates/core/macros.jinja:27 #: core/templates/core/macros.jinja:27 core/templates/core/user_detail.jinja:27
#: core/templates/core/user_detail.jinja:27
msgid "Born: " msgid "Born: "
msgstr "Né le : " msgstr "Né le : "
#: core/templates/core/macros.jinja:31 #: core/templates/core/macros.jinja:31 core/templates/core/user_detail.jinja:48
#: core/templates/core/user_detail.jinja:48
msgid "Promo: " msgid "Promo: "
msgstr "Promo : " msgstr "Promo : "
@ -1588,8 +1586,7 @@ msgstr "Résultat de la recherche"
msgid "Users" msgid "Users"
msgstr "Utilisateurs" msgstr "Utilisateurs"
#: core/templates/core/search.jinja:18 #: core/templates/core/search.jinja:18 counter/templates/counter/stats.jinja:17
#: counter/templates/counter/stats.jinja:17
msgid "Clubs" msgid "Clubs"
msgstr "Clubs" msgstr "Clubs"
@ -1629,7 +1626,11 @@ msgstr "Achat sur compte utilisateur"
msgid "Eboutic invoices" msgid "Eboutic invoices"
msgstr "Facture eboutic" 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 #: core/templates/core/user_account_detail.jinja:103
msgid "User has no account" msgid "User has no account"
msgstr "L'utilisateur n'a pas de compte" msgstr "L'utilisateur n'a pas de compte"
@ -1790,7 +1791,7 @@ msgid "Subscriptions"
msgstr "Cotisations" msgstr "Cotisations"
#: core/templates/core/user_tools.jinja:23 counter/views.py:440 #: core/templates/core/user_tools.jinja:23 counter/views.py:440
#: counter/views.py:584 #: counter/views.py:589
msgid "Counters" msgid "Counters"
msgstr "Comptoirs" msgstr "Comptoirs"
@ -1888,83 +1889,83 @@ msgstr "Fillot"
msgid "User already has a profile picture" msgid "User already has a profile picture"
msgstr "L'utilisateur a déjà une photo de profil" msgstr "L'utilisateur a déjà une photo de profil"
#: counter/models.py:24 #: counter/models.py:26
msgid "account id" msgid "account id"
msgstr "numéro de compte" msgstr "numéro de compte"
#: counter/models.py:28 #: counter/models.py:30
msgid "customer" msgid "customer"
msgstr "client" msgstr "client"
#: counter/models.py:29 #: counter/models.py:31
msgid "customers" msgid "customers"
msgstr "clients" 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" msgid "Not enough money"
msgstr "Solde insuffisant" msgstr "Solde insuffisant"
#: counter/models.py:65 counter/models.py:87 #: counter/models.py:67 counter/models.py:89
msgid "product type" msgid "product type"
msgstr "type du produit" msgstr "type du produit"
#: counter/models.py:90 #: counter/models.py:92
msgid "purchase price" msgid "purchase price"
msgstr "prix d'achat" msgstr "prix d'achat"
#: counter/models.py:91 #: counter/models.py:93
msgid "selling price" msgid "selling price"
msgstr "prix de vente" msgstr "prix de vente"
#: counter/models.py:92 #: counter/models.py:94
msgid "special selling price" msgid "special selling price"
msgstr "prix de vente spécial" msgstr "prix de vente spécial"
#: counter/models.py:93 #: counter/models.py:95
msgid "icon" msgid "icon"
msgstr "icône" msgstr "icône"
#: counter/models.py:95 #: counter/models.py:97
msgid "limit age" msgid "limit age"
msgstr "âge limite" msgstr "âge limite"
#: counter/models.py:96 #: counter/models.py:98
msgid "tray price" msgid "tray price"
msgstr "prix plateau" msgstr "prix plateau"
#: counter/models.py:97 #: counter/models.py:99
msgid "parent product" msgid "parent product"
msgstr "produit parent" msgstr "produit parent"
#: counter/models.py:99 #: counter/models.py:101
msgid "buying groups" msgid "buying groups"
msgstr "groupe d'achat" msgstr "groupe d'achat"
#: counter/models.py:100 #: counter/models.py:102
msgid "archived" msgid "archived"
msgstr "archivé" msgstr "archivé"
#: counter/models.py:103 #: counter/models.py:105 counter/models.py:439
msgid "product" msgid "product"
msgstr "produit" msgstr "produit"
#: counter/models.py:122 #: counter/models.py:124
msgid "products" msgid "products"
msgstr "produits" msgstr "produits"
#: counter/models.py:123 #: counter/models.py:125
msgid "counter type" msgid "counter type"
msgstr "type de comptoir" msgstr "type de comptoir"
#: counter/models.py:125 #: counter/models.py:127
msgid "Bar" msgid "Bar"
msgstr "Bar" msgstr "Bar"
#: counter/models.py:125 #: counter/models.py:127
msgid "Office" msgid "Office"
msgstr "Bureau" 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:4
#: eboutic/templates/eboutic/eboutic_main.jinja:24 #: eboutic/templates/eboutic/eboutic_main.jinja:24
#: eboutic/templates/eboutic/eboutic_makecommand.jinja:8 #: eboutic/templates/eboutic/eboutic_makecommand.jinja:8
@ -1973,84 +1974,100 @@ msgstr "Bureau"
msgid "Eboutic" msgid "Eboutic"
msgstr "Eboutic" msgstr "Eboutic"
#: counter/models.py:126 #: counter/models.py:128
msgid "sellers" msgid "sellers"
msgstr "vendeurs" msgstr "vendeurs"
#: counter/models.py:129 launderette/models.py:125 #: counter/models.py:131 launderette/models.py:125
msgid "token" msgid "token"
msgstr "jeton" 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 #: launderette/models.py:16
msgid "counter" msgid "counter"
msgstr "comptoir" msgstr "comptoir"
#: counter/models.py:230 #: counter/models.py:232
msgid "bank" msgid "bank"
msgstr "banque" msgstr "banque"
#: counter/models.py:232 counter/models.py:273 #: counter/models.py:234 counter/models.py:275
msgid "is validated" msgid "is validated"
msgstr "est validé" msgstr "est validé"
#: counter/models.py:235 #: counter/models.py:237
msgid "refilling" msgid "refilling"
msgstr "rechargement" msgstr "rechargement"
#: counter/models.py:266 eboutic/models.py:103 #: counter/models.py:268 eboutic/models.py:103
msgid "unit price" msgid "unit price"
msgstr "prix unitaire" 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" msgid "quantity"
msgstr "quantité" msgstr "quantité"
#: counter/models.py:272 #: counter/models.py:274
msgid "Sith account" msgid "Sith account"
msgstr "Compte utilisateur" 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 #: sith/settings.py:298
msgid "Credit card" msgid "Credit card"
msgstr "Carte bancaire" msgstr "Carte bancaire"
#: counter/models.py:276 #: counter/models.py:278
msgid "selling" msgid "selling"
msgstr "vente" msgstr "vente"
#: counter/models.py:338 #: counter/models.py:343
msgid "last activity date" msgid "last activity date"
msgstr "dernière activité" msgstr "dernière activité"
#: counter/models.py:341 #: counter/models.py:346
msgid "permanency" msgid "permanency"
msgstr "permanence" msgstr "permanence"
#: counter/models.py:355 #: counter/models.py:360
msgid "emptied" msgid "emptied"
msgstr "coffre vidée" msgstr "coffre vidée"
#: counter/models.py:358 #: counter/models.py:363
msgid "cash register summary" msgid "cash register summary"
msgstr "relevé de caisse" msgstr "relevé de caisse"
#: counter/models.py:422 #: counter/models.py:427
msgid "cash summary" msgid "cash summary"
msgstr "relevé" msgstr "relevé"
#: counter/models.py:423 #: counter/models.py:428
msgid "value" msgid "value"
msgstr "valeur" msgstr "valeur"
#: counter/models.py:425 #: counter/models.py:430
msgid "check" msgid "check"
msgstr "chèque" msgstr "chèque"
#: counter/models.py:428 #: counter/models.py:433
msgid "cash register summary item" msgid "cash register summary item"
msgstr "élément de relevé de caisse" 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:5
#: counter/templates/counter/activity.jinja:9 #: counter/templates/counter/activity.jinja:9
#, python-format #, python-format
@ -2074,7 +2091,7 @@ msgstr "Liste des relevés de caisse"
msgid "Theoric sums" msgid "Theoric sums"
msgstr "Sommes théoriques" 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" msgid "Emptied"
msgstr "Coffre vidé" msgstr "Coffre vidé"
@ -2181,6 +2198,19 @@ msgstr "Merci de vous identifier"
msgid "Barman: " msgid "Barman: "
msgstr "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 #: counter/templates/counter/invoices_call.jinja:4 counter/views.py:465
msgid "Invoices call" msgid "Invoices call"
msgstr "Appels à facture" msgstr "Appels à facture"
@ -2305,61 +2335,61 @@ msgstr "Produits archivés"
msgid "Product types" msgid "Product types"
msgstr "Types de produit" msgstr "Types de produit"
#: counter/views.py:581 #: counter/views.py:586
msgid "Parent product" msgid "Parent product"
msgstr "Produit parent" msgstr "Produit parent"
#: counter/views.py:582 #: counter/views.py:587
msgid "Buying groups" msgid "Buying groups"
msgstr "Groupes d'achat" msgstr "Groupes d'achat"
#: counter/views.py:677 #: counter/views.py:682
msgid "10 cents" msgid "10 cents"
msgstr "10 centimes" msgstr "10 centimes"
#: counter/views.py:678 #: counter/views.py:683
msgid "20 cents" msgid "20 cents"
msgstr "20 centimes" msgstr "20 centimes"
#: counter/views.py:679 #: counter/views.py:684
msgid "50 cents" msgid "50 cents"
msgstr "50 centimes" msgstr "50 centimes"
#: counter/views.py:680 #: counter/views.py:685
msgid "1 euro" msgid "1 euro"
msgstr "1 €" msgstr "1 €"
#: counter/views.py:681 #: counter/views.py:686
msgid "2 euros" msgid "2 euros"
msgstr "2 €" msgstr "2 €"
#: counter/views.py:682 #: counter/views.py:687
msgid "5 euros" msgid "5 euros"
msgstr "5 €" msgstr "5 €"
#: counter/views.py:683 #: counter/views.py:688
msgid "10 euros" msgid "10 euros"
msgstr "10 €" msgstr "10 €"
#: counter/views.py:684 #: counter/views.py:689
msgid "20 euros" msgid "20 euros"
msgstr "20 €" msgstr "20 €"
#: counter/views.py:685 #: counter/views.py:690
msgid "50 euros" msgid "50 euros"
msgstr "50 €" msgstr "50 €"
#: counter/views.py:686 #: counter/views.py:691
msgid "100 euros" msgid "100 euros"
msgstr "100 €" msgstr "100 €"
#: counter/views.py:687 counter/views.py:689 counter/views.py:691 #: counter/views.py:692 counter/views.py:694 counter/views.py:696
#: counter/views.py:693 counter/views.py:695 #: counter/views.py:698 counter/views.py:700
msgid "Check amount" msgid "Check amount"
msgstr "Montant du chèque" msgstr "Montant du chèque"
#: counter/views.py:688 counter/views.py:690 counter/views.py:692 #: counter/views.py:693 counter/views.py:695 counter/views.py:697
#: counter/views.py:694 counter/views.py:696 #: counter/views.py:699 counter/views.py:701
msgid "Check quantity" msgid "Check quantity"
msgstr "Nombre de chèque" msgstr "Nombre de chèque"
@ -2720,5 +2750,14 @@ msgid "You must either choose an existing user or create a new one properly"
msgstr "" msgstr ""
"Vous devez soit choisir un utilisateur existant, ou en créer un proprement." "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" #~ msgid "Display last operations"
#~ msgstr "Dernières opérations" #~ msgstr "Dernières opérations"

View File

@ -8,4 +8,6 @@ pytz
djangorestframework djangorestframework
django-phonenumber-field django-phonenumber-field
django-ajax-selects django-ajax-selects
reportlab
# mysqlclient # mysqlclient