From a0f7150c55fe555467f98aa98c0c170303309ef6 Mon Sep 17 00:00:00 2001 From: Skia Date: Sun, 7 Aug 2016 20:10:50 +0200 Subject: [PATCH] Update accounting to have a target --- .../migrations/0013_auto_20160807_1923.py | 40 ++++ .../migrations/0015_auto_20160807_1959.py | 24 ++ .../migrations/0016_auto_20160807_2000.py | 18 ++ accounting/models.py | 51 +++- .../accounting/journal_details.jinja | 9 +- accounting/urls.py | 3 + accounting/views.py | 27 ++- club/models.py | 3 + core/management/commands/populate.py | 20 +- locale/fr/LC_MESSAGES/django.mo | Bin 21424 -> 22040 bytes locale/fr/LC_MESSAGES/django.po | 225 +++++++++++------- 11 files changed, 318 insertions(+), 102 deletions(-) create mode 100644 accounting/migrations/0013_auto_20160807_1923.py create mode 100644 accounting/migrations/0015_auto_20160807_1959.py create mode 100644 accounting/migrations/0016_auto_20160807_2000.py diff --git a/accounting/migrations/0013_auto_20160807_1923.py b/accounting/migrations/0013_auto_20160807_1923.py new file mode 100644 index 00000000..15f7ee91 --- /dev/null +++ b/accounting/migrations/0013_auto_20160807_1923.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounting', '0012_auto_20160720_1847'), + ] + + operations = [ + migrations.CreateModel( + name='Company', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False, auto_created=True, verbose_name='ID')), + ('name', models.CharField(max_length=60, verbose_name='name')), + ], + options={ + 'verbose_name': 'company', + }, + ), + migrations.AddField( + model_name='operation', + name='target_id', + field=models.IntegerField(blank=True, null=True, verbose_name='target id'), + ), + migrations.AddField( + model_name='operation', + name='target_label', + field=models.CharField(max_length=32, blank=True, default='', verbose_name='target label'), + ), + migrations.AddField( + model_name='operation', + name='target_type', + field=models.CharField(max_length=10, default='OTHER', choices=[('USER', 'User'), ('CLUB', 'Club'), ('ACCOUNT', 'Account'), ('COMPANY', 'Company'), ('OTHER', 'Other')], verbose_name='target type'), + preserve_default=False, + ), + ] diff --git a/accounting/migrations/0015_auto_20160807_1959.py b/accounting/migrations/0015_auto_20160807_1959.py new file mode 100644 index 00000000..3bb17ae0 --- /dev/null +++ b/accounting/migrations/0015_auto_20160807_1959.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounting', '0014_auto_20160807_1954'), + ] + + operations = [ + migrations.AlterField( + model_name='operation', + name='accounting_type', + field=models.ForeignKey(related_name='operations', verbose_name='accounting type', to='accounting.AccountingType'), + ), + migrations.AlterField( + model_name='operation', + name='invoice', + field=models.FileField(upload_to='invoices', verbose_name='invoice', null=True, blank=True), + ), + ] diff --git a/accounting/migrations/0016_auto_20160807_2000.py b/accounting/migrations/0016_auto_20160807_2000.py new file mode 100644 index 00000000..64767ee7 --- /dev/null +++ b/accounting/migrations/0016_auto_20160807_2000.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounting', '0015_auto_20160807_1959'), + ] + + operations = [ + migrations.AlterModelOptions( + name='accountingtype', + options={'verbose_name': 'accounting type'}, + ), + ] diff --git a/accounting/models.py b/accounting/models.py index 616b5352..370b3bc4 100644 --- a/accounting/models.py +++ b/accounting/models.py @@ -27,6 +27,19 @@ class CurrencyField(models.DecimalField): except AttributeError: return None +# Accounting classes + +class Company(models.Model): + name = models.CharField(_('name'), max_length=60) + + class Meta: + verbose_name = _("company") + + def get_absolute_url(self): + return reverse('accounting:co_edit', kwargs={'co_id': self.id}) + + def get_display_name(self): + return self.name class BankAccount(models.Model): name = models.CharField(_('name'), max_length=30) @@ -85,6 +98,10 @@ class ClubAccount(models.Model): def __str__(self): return self.name + def get_display_name(self): + return _("%(club_account)s on %(bank_account)s") % {"club_account": self.name, "bank_account": self.bank_account} + + class GeneralJournal(models.Model): """ Class storing all the operations for a period of time @@ -139,19 +156,45 @@ class Operation(models.Model): remark = models.TextField(_('remark'), max_length=255) mode = models.CharField(_('payment method'), max_length=255, choices=settings.SITH_ACCOUNTING_PAYMENT_METHOD) cheque_number = models.IntegerField(_('cheque number'), default=-1) - invoice = models.FileField(upload_to='invoices', null=True, blank=True) + invoice = models.FileField(upload_to='invoices', verbose_name=_("invoice"), null=True, blank=True) done = models.BooleanField(_('is done'), default=False) - accounting_type = models.ForeignKey('AccountingType', related_name="operations") + accounting_type = models.ForeignKey('AccountingType', related_name="operations", verbose_name=_("accounting type")) + target_type = models.CharField(_('target type'), max_length=10, + choices=[('USER', _('User')), ('CLUB', _('Club')), ('ACCOUNT', _('Account')), ('COMPANY', _('Company')), ('OTHER', _('Other'))]) + target_id = models.IntegerField(_('target id'), null=True, blank=True) + target_label = models.CharField(_('target label'), max_length=32, default="", blank=True) class Meta: unique_together = ('number', 'journal') ordering = ['-number'] + def __getattribute__(self, attr): + if attr == "target": + return self.get_target() + else: + return object.__getattribute__(self, attr) + def clean(self): super(Operation, self).clean() if self.date < self.journal.start_date: raise ValidationError(_("""The date can not be before the start date of the journal, which is %(start_date)s.""") % {'start_date': defaultfilters.date(self.journal.start_date, settings.DATE_FORMAT)}) + if self.target_type != "OTHER" and self.get_target() is None: + raise ValidationError(_("Target does not exists")) + if self.target_type == "OTHER" and self.target_label == "": + raise ValidationError(_("Please add a target label if you set no existing target")) + + def get_target(self): + tar = None + if self.target_type == "USER": + tar = User.objects.filter(id=self.target_id).first() + elif self.target_type == "CLUB": + tar = Club.objects.filter(id=self.target_id).first() + elif self.target_type == "ACCOUNT": + tar = ClubAccount.objects.filter(id=self.target_id).first() + elif self.target_type == "COMPANY": + tar = Company.objects.filter(id=self.target_id).first() + return tar def save(self): if self.number is None: @@ -198,6 +241,9 @@ class AccountingType(models.Model): label = models.CharField(_('label'), max_length=60) movement_type = models.CharField(_('movement type'), choices=[('credit', 'Credit'), ('debit', 'Debit'), ('neutral', 'Neutral')], max_length=12) + class Meta: + verbose_name = _("accounting type") + def is_owned_by(self, user): """ Method to see if that object can be edited by the given user @@ -211,4 +257,3 @@ class AccountingType(models.Model): def __str__(self): return self.movement_type+" - "+self.code+" - "+self.label - diff --git a/accounting/templates/accounting/journal_details.jinja b/accounting/templates/accounting/journal_details.jinja index ae4286d0..bcc8ba1c 100644 --- a/accounting/templates/accounting/journal_details.jinja +++ b/accounting/templates/accounting/journal_details.jinja @@ -22,7 +22,7 @@ {% trans %}Label{% endtrans %} {% trans %}Amount{% endtrans %} {% trans %}Payment mode{% endtrans %} - + {% trans %}Target{% endtrans %} {% trans %}Code{% endtrans %} {% trans %}Nature{% endtrans %} {% trans %}Done{% endtrans %} @@ -37,7 +37,12 @@ {{ o.date }} {{ o.label }} {{ o.amount }} € - {{ o.mode }} + {{ o.get_mode_display() }} + {% if o.target_type == "OTHER" %} + {{ o.target_label }} + {% else %} + {{ o.target.get_display_name() }} + {% endif %} {{ o.accounting_type.code }} {{ o.accounting_type.label }} {% if o.done %} diff --git a/accounting/urls.py b/accounting/urls.py index 33e62379..e004d068 100644 --- a/accounting/urls.py +++ b/accounting/urls.py @@ -25,6 +25,9 @@ urlpatterns = [ # Operations url(r'^operation/create$', OperationCreateView.as_view(), name='op_new'), url(r'^operation/(?P[0-9]+)$', OperationEditView.as_view(), name='op_edit'), + # Companies + url(r'^company/create$', CompanyCreateView.as_view(), name='co_new'), + url(r'^company/(?P[0-9]+)$', CompanyEditView.as_view(), name='co_edit'), ] diff --git a/accounting/views.py b/accounting/views.py index 473e2457..109599dc 100644 --- a/accounting/views.py +++ b/accounting/views.py @@ -6,7 +6,7 @@ from django.forms.models import modelform_factory from django.forms import HiddenInput from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin -from accounting.models import BankAccount, ClubAccount, GeneralJournal, Operation, AccountingType +from accounting.models import BankAccount, ClubAccount, GeneralJournal, Operation, AccountingType, Company # Accounting types @@ -164,7 +164,8 @@ class OperationCreateView(CanCreateMixin, CreateView): """ model = Operation form_class = modelform_factory(Operation, - fields=['amount', 'label', 'remark', 'journal', 'date', 'mode', 'cheque_number', 'accounting_type', 'done'], + fields=['amount', 'label', 'remark', 'journal', 'target_type', 'target_id', 'target_label', 'date', 'mode', + 'cheque_number', 'invoice', 'accounting_type', 'done'], widgets={'journal': HiddenInput}) template_name = 'core/create.jinja' @@ -182,6 +183,26 @@ class OperationEditView(CanEditMixin, UpdateView): """ model = Operation pk_url_kwarg = "op_id" - fields = ['amount', 'label', 'remark', 'date', 'mode', 'cheque_number', 'accounting_type', 'done'] + fields = ['amount', 'label', 'remark', 'target_type', 'target_id', 'target_label', 'date', 'mode', 'cheque_number', + 'invoice', 'accounting_type', 'done'] + template_name = 'core/edit.jinja' + +# Company views + +class CompanyCreateView(CanCreateMixin, CreateView): + """ + Create a company + """ + model = Company + fields = ['name'] + template_name = 'core/create.jinja' + +class CompanyEditView(CanCreateMixin, UpdateView): + """ + Edit a company + """ + model = Company + pk_url_kwarg = "co_id" + fields = ['name'] template_name = 'core/edit.jinja' diff --git a/club/models.py b/club/models.py index f0dd07d0..9997b57e 100644 --- a/club/models.py +++ b/club/models.py @@ -61,6 +61,9 @@ class Club(models.Model): def get_absolute_url(self): return reverse('club:club_view', kwargs={'club_id': self.id}) + def get_display_name(self): + return self.name + def is_owned_by(self, user): """ Method to see if that object can be super edited by the given user diff --git a/core/management/commands/populate.py b/core/management/commands/populate.py index ed1d0bc5..bf1c6cb0 100644 --- a/core/management/commands/populate.py +++ b/core/management/commands/populate.py @@ -1,5 +1,5 @@ import os -from datetime import date +from datetime import date, datetime from io import StringIO from django.core.management.base import BaseCommand, CommandError @@ -9,7 +9,7 @@ from django.db import connection from core.models import Group, User, Page, PageRev -from accounting.models import GeneralJournal, BankAccount, ClubAccount, Operation, AccountingType +from accounting.models import GeneralJournal, BankAccount, ClubAccount, Operation, AccountingType, Company from club.models import Club, Membership from subscription.models import Subscription, Subscriber from counter.models import Customer, ProductType, Product, Counter @@ -239,6 +239,18 @@ Cette page vise à documenter la syntaxe *Markdown* utilisée sur le site. ba.save() ca = ClubAccount(name="Troll Penché", bank_account=ba, club=troll) ca.save() - AccountingType(code=756, label="Someone gave us money", movement_type='credit').save() - AccountingType(code=8570, label="Had to pay for food", movement_type='debit').save() + gj = GeneralJournal(name="A16", start_date=date.today(), club_account=ca) + gj.save() + credit = AccountingType(code=74, label="Someone gave us money", movement_type='credit') + credit.save() + debit = AccountingType(code=607, label="Had to pay a beer", movement_type='debit') + debit.save() + Operation(journal=gj, date=date.today(), amount=666.42, label="Satanic answer", + remark="An answer to life...", mode="CASH", done=True, accounting_type=credit, target_type="USER", + target_id=skia.id).save() + Operation(journal=gj, date=date.today(), amount=42, label="Answer", + remark="An answer to life...", mode="CASH", done=False, accounting_type=debit, target_type="CLUB", + target_id=bar_club.id).save() + woenzco = Company(name="Woenzel & co") + woenzco.save() diff --git a/locale/fr/LC_MESSAGES/django.mo b/locale/fr/LC_MESSAGES/django.mo index 07e5df2f0824c0e6a00951566c14303a157f94be..a30f51fa821e54998fa052e0ec562609f69e3798 100644 GIT binary patch delta 7987 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 Di`{@) delta 7406 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\n" "Language-Team: AE info \n" @@ -16,74 +16,124 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: accounting/models.py:32 accounting/models.py:55 accounting/models.py:94 -#: club/models.py:18 counter/models.py:52 counter/models.py:77 -#: counter/models.py:105 launderette/models.py:14 launderette/models.py:42 -#: launderette/models.py:65 +#: accounting/models.py:33 accounting/models.py:45 accounting/models.py:68 +#: accounting/models.py:111 club/models.py:18 counter/models.py:52 +#: counter/models.py:77 counter/models.py:105 launderette/models.py:14 +#: launderette/models.py:42 launderette/models.py:65 msgid "name" msgstr "nom" -#: accounting/models.py:33 +#: accounting/models.py:36 +msgid "company" +msgstr "entreprise" + +#: accounting/models.py:46 msgid "iban" msgstr "IBAN" -#: accounting/models.py:34 +#: accounting/models.py:47 msgid "account number" msgstr "numero de compte" -#: accounting/models.py:92 club/models.py:109 counter/models.py:259 +#: accounting/models.py:102 +#, python-format +msgid "%(club_account)s on %(bank_account)s" +msgstr "%(club_account)s sur %(bank_account)s" + +#: accounting/models.py:109 club/models.py:112 counter/models.py:259 #: launderette/models.py:94 msgid "start date" msgstr "date de début" -#: accounting/models.py:93 club/models.py:110 counter/models.py:260 +#: accounting/models.py:110 club/models.py:113 counter/models.py:260 msgid "end date" msgstr "date de fin" -#: accounting/models.py:95 +#: accounting/models.py:112 msgid "is closed" msgstr "est fermé" -#: accounting/models.py:97 accounting/models.py:136 counter/models.py:25 +#: accounting/models.py:114 accounting/models.py:153 counter/models.py:25 #: counter/models.py:197 msgid "amount" msgstr "montant" -#: accounting/models.py:98 +#: accounting/models.py:115 msgid "effective_amount" msgstr "montant effectif" -#: accounting/models.py:134 +#: accounting/models.py:151 msgid "number" msgstr "numéro" -#: accounting/models.py:137 core/models.py:466 counter/models.py:200 +#: accounting/models.py:154 core/models.py:466 counter/models.py:200 #: counter/models.py:235 eboutic/models.py:13 eboutic/models.py:46 msgid "date" msgstr "date" -#: accounting/models.py:138 accounting/models.py:198 counter/models.py:228 +#: accounting/models.py:155 accounting/models.py:241 counter/models.py:228 msgid "label" msgstr "intitulé" -#: accounting/models.py:139 +#: accounting/models.py:156 msgid "remark" msgstr "remarque" -#: accounting/models.py:140 counter/models.py:201 eboutic/models.py:48 +#: accounting/models.py:157 counter/models.py:201 eboutic/models.py:48 #: subscription/models.py:34 msgid "payment method" msgstr "méthode de paiement" -#: accounting/models.py:141 +#: accounting/models.py:158 msgid "cheque number" msgstr "numéro de chèque" -#: accounting/models.py:143 +#: accounting/models.py:159 eboutic/models.py:92 +msgid "invoice" +msgstr "facture" + +#: accounting/models.py:160 msgid "is done" msgstr "est fait" -#: accounting/models.py:153 +#: accounting/models.py:161 accounting/models.py:245 +msgid "accounting type" +msgstr "type comptable" + +#: accounting/models.py:162 +msgid "target type" +msgstr "type de cible" + +#: accounting/models.py:163 +#: launderette/templates/launderette/launderette_admin.jinja:34 +msgid "User" +msgstr "Utilisateur" + +#: accounting/models.py:163 club/templates/club/club_detail.jinja:4 +msgid "Club" +msgstr "Club" + +#: accounting/models.py:163 core/templates/core/user_base.jinja:16 +msgid "Account" +msgstr "Compte" + +#: accounting/models.py:163 +msgid "Company" +msgstr "Entreprise" + +#: accounting/models.py:163 sith/settings.py:259 sith/settings_sample.py:259 +msgid "Other" +msgstr "Autre" + +#: accounting/models.py:164 +msgid "target id" +msgstr "id de la cible" + +#: accounting/models.py:165 +msgid "target label" +msgstr "nom de la cible" + +#: accounting/models.py:180 #, python-format msgid "" "The date can not be before the start date of the journal, which is\n" @@ -92,11 +142,20 @@ msgstr "" "La date ne peut pas être avant la date de début du journal, qui est\n" "%(start_date)s." -#: accounting/models.py:197 counter/models.py:80 +#: accounting/models.py:183 +msgid "Target does not exists" +msgstr "La cible n'existe pas." + +#: accounting/models.py:185 +msgid "Please add a target label if you set no existing target" +msgstr "" +"Merci d'ajouter un nom de cible si vous ne spécifiez pas de cible existante" + +#: accounting/models.py:240 counter/models.py:80 msgid "code" msgstr "code" -#: accounting/models.py:199 +#: accounting/models.py:242 msgid "movement type" msgstr "type de mouvement" @@ -145,7 +204,7 @@ msgstr "Nouveau compte club" #: accounting/templates/accounting/bank_account_details.jinja:18 #: accounting/templates/accounting/bank_account_list.jinja:15 #: accounting/templates/accounting/club_account_details.jinja:44 -#: accounting/templates/accounting/journal_details.jinja:51 +#: accounting/templates/accounting/journal_details.jinja:56 #: club/templates/club/club_detail.jinja:7 core/templates/core/page.jinja:31 #: core/templates/core/user_base.jinja:8 #: core/templates/core/user_tools.jinja:37 @@ -159,7 +218,7 @@ msgstr "Éditer" #: accounting/templates/accounting/bank_account_list.jinja:16 #: core/templates/core/group_list.jinja:13 #: launderette/templates/launderette/launderette_admin.jinja:16 -#: launderette/views.py:147 +#: launderette/views.py:146 msgid "Delete" msgstr "Supprimer" @@ -226,12 +285,12 @@ msgid "Actions" msgstr "Actions" #: accounting/templates/accounting/club_account_details.jinja:39 -#: accounting/templates/accounting/journal_details.jinja:44 +#: accounting/templates/accounting/journal_details.jinja:49 msgid "Yes" msgstr "Oui" #: accounting/templates/accounting/club_account_details.jinja:41 -#: accounting/templates/accounting/journal_details.jinja:46 +#: accounting/templates/accounting/journal_details.jinja:51 msgid "No" msgstr "Non" @@ -277,6 +336,10 @@ msgstr "Intitulé" msgid "Payment mode" msgstr "Méthode de paiement" +#: accounting/templates/accounting/journal_details.jinja:25 +msgid "Target" +msgstr "Cible" + #: accounting/templates/accounting/journal_details.jinja:26 msgid "Code" msgstr "Code" @@ -317,40 +380,36 @@ msgstr "Adresse" msgid "You can not make loops in clubs" msgstr "Vous ne pouvez pas faire de boucles dans les clubs" -#: club/models.py:107 eboutic/models.py:12 eboutic/models.py:45 +#: club/models.py:110 eboutic/models.py:12 eboutic/models.py:45 #: launderette/models.py:69 launderette/models.py:98 msgid "user" msgstr "nom d'utilisateur" -#: club/models.py:108 +#: club/models.py:111 msgid "club" msgstr "club" -#: club/models.py:111 +#: club/models.py:114 msgid "role" msgstr "rôle" -#: club/models.py:113 core/models.py:27 counter/models.py:53 +#: club/models.py:116 core/models.py:27 counter/models.py:53 #: counter/models.py:78 msgid "description" msgstr "description" -#: club/models.py:118 +#: club/models.py:121 msgid "User must be subscriber to take part to a club" msgstr "L'utilisateur doit être cotisant pour faire partie d'un club" -#: club/models.py:120 +#: club/models.py:123 msgid "User is already member of that club" msgstr "L'utilisateur est déjà membre de ce club" -#: club/models.py:124 +#: club/models.py:127 msgid "past member" msgstr "Anciens membres" -#: club/templates/club/club_detail.jinja:4 -msgid "Club" -msgstr "Club" - #: club/templates/club/club_detail.jinja:5 #: core/templates/core/group_edit.jinja:4 msgid "Back to list" @@ -398,7 +457,7 @@ msgstr "Il n'y a pas de club dans ce site web." msgid "Club members" msgstr "Membres du club" -#: club/templates/club/club_members.jinja:13 launderette/views.py:147 +#: club/templates/club/club_members.jinja:13 launderette/views.py:146 msgid "Add" msgstr "Ajouter" @@ -857,10 +916,6 @@ msgstr "L'utilisateur n'a pas de compte" msgid "Groups" msgstr "Groupes" -#: core/templates/core/user_base.jinja:16 -msgid "Account" -msgstr "Compte" - #: core/templates/core/user_detail.jinja:4 #, python-format msgid "%(user_name)s's profile" @@ -1195,7 +1250,7 @@ msgstr "ANN" msgid "You have not enough money to buy all the basket" msgstr "Vous n'avez pas assez d'argent pour acheter le panier" -#: eboutic/models.py:47 sith/settings.py:252 sith/settings_sample.py:251 +#: eboutic/models.py:47 sith/settings.py:253 sith/settings_sample.py:253 msgid "Credit card" msgstr "Carte banquaire" @@ -1223,10 +1278,6 @@ msgstr "nom du produit" msgid "basket" msgstr "panier" -#: eboutic/models.py:92 -msgid "invoice" -msgstr "facture" - #: eboutic/templates/eboutic/eboutic_main.jinja:33 msgid "Proceed to command" msgstr "Procéder à la commande" @@ -1323,14 +1374,10 @@ msgid "Tokens" msgstr "Jetons" #: launderette/templates/launderette/launderette_admin.jinja:32 -#: launderette/views.py:148 +#: launderette/views.py:147 msgid "Type" msgstr "Type" -#: launderette/templates/launderette/launderette_admin.jinja:34 -msgid "User" -msgstr "Utilisateur" - #: launderette/templates/launderette/launderette_admin.jinja:35 msgid "Since" msgstr "Depuis" @@ -1344,12 +1391,12 @@ msgid "Washing and drying" msgstr "Lavage et séchage" #: launderette/templates/launderette/launderette_book.jinja:26 -#: sith/settings.py:340 sith/settings_sample.py:339 +#: sith/settings.py:341 sith/settings_sample.py:341 msgid "Washing" msgstr "Lavage" #: launderette/templates/launderette/launderette_book.jinja:30 -#: sith/settings.py:340 sith/settings_sample.py:339 +#: sith/settings.py:341 sith/settings_sample.py:341 msgid "Drying" msgstr "Séchage" @@ -1374,115 +1421,113 @@ msgstr "Éditer la page de présentation" msgid "Book launderette slot" msgstr "Réserver un créneau de laverie" -#: launderette/views.py:147 +#: launderette/views.py:146 msgid "Back" msgstr "Retour" -#: launderette/views.py:147 +#: launderette/views.py:146 msgid "Action" msgstr "Action" -#: launderette/views.py:149 +#: launderette/views.py:148 msgid "Tokens, separated by spaces" msgstr "Jetons, séparés par des espaces" -#: launderette/views.py:164 launderette/views.py:178 +#: launderette/views.py:163 launderette/views.py:177 +#, python-format msgid "Token %(token_name)s does not exists" msgstr "Le jeton %(token_name)s n'existe pas" -#: launderette/views.py:172 +#: launderette/views.py:171 +#, python-format msgid "Token %(token_name)s already exists" msgstr "Un jeton %(token_name)s existe déjà" -#: launderette/views.py:230 +#: launderette/views.py:227 msgid "User has booked no slot" msgstr "L'utilisateur n'a pas réservé de créneau" -#: launderette/views.py:320 +#: launderette/views.py:317 msgid "Token not found" msgstr "Jeton non trouvé" -#: sith/settings.py:249 sith/settings.py:256 sith/settings.py:274 -#: sith/settings_sample.py:248 sith/settings_sample.py:255 -#: sith/settings_sample.py:273 +#: sith/settings.py:250 sith/settings.py:257 sith/settings.py:275 +#: sith/settings_sample.py:250 sith/settings_sample.py:257 +#: sith/settings_sample.py:275 msgid "Check" msgstr "Chèque" -#: sith/settings.py:250 sith/settings.py:257 sith/settings.py:275 -#: sith/settings_sample.py:249 sith/settings_sample.py:256 -#: sith/settings_sample.py:274 +#: sith/settings.py:251 sith/settings.py:258 sith/settings.py:276 +#: sith/settings_sample.py:251 sith/settings_sample.py:258 +#: sith/settings_sample.py:276 msgid "Cash" msgstr "Espèces" -#: sith/settings.py:251 sith/settings_sample.py:250 +#: sith/settings.py:252 sith/settings_sample.py:252 msgid "Transfert" msgstr "Virement" -#: sith/settings.py:258 sith/settings_sample.py:257 -msgid "Other" -msgstr "Autre" - -#: sith/settings.py:262 sith/settings_sample.py:261 +#: sith/settings.py:263 sith/settings_sample.py:263 msgid "Belfort" msgstr "Belfort" -#: sith/settings.py:263 sith/settings_sample.py:262 +#: sith/settings.py:264 sith/settings_sample.py:264 msgid "Sevenans" msgstr "Sevenans" -#: sith/settings.py:264 sith/settings_sample.py:263 +#: sith/settings.py:265 sith/settings_sample.py:265 msgid "Montbéliard" msgstr "Montbéliard" -#: sith/settings.py:288 sith/settings_sample.py:287 +#: sith/settings.py:289 sith/settings_sample.py:289 msgid "One semester" msgstr "Un semestre" -#: sith/settings.py:293 sith/settings_sample.py:292 +#: sith/settings.py:294 sith/settings_sample.py:294 msgid "Two semesters" msgstr "Deux semestres" -#: sith/settings.py:298 sith/settings_sample.py:297 +#: sith/settings.py:299 sith/settings_sample.py:299 msgid "Common core cursus" msgstr "Cursus tronc commun" -#: sith/settings.py:303 sith/settings_sample.py:302 +#: sith/settings.py:304 sith/settings_sample.py:304 msgid "Branch cursus" msgstr "Cursus branche" -#: sith/settings.py:311 sith/settings_sample.py:310 +#: sith/settings.py:312 sith/settings_sample.py:312 msgid "President" msgstr "Président" -#: sith/settings.py:312 sith/settings_sample.py:311 +#: sith/settings.py:313 sith/settings_sample.py:313 msgid "Vice-President" msgstr "Vice-Président" -#: sith/settings.py:313 sith/settings_sample.py:312 +#: sith/settings.py:314 sith/settings_sample.py:314 msgid "Treasurer" msgstr "Trésorier" -#: sith/settings.py:314 sith/settings_sample.py:313 +#: sith/settings.py:315 sith/settings_sample.py:315 msgid "Communication supervisor" msgstr "Responsable com" -#: sith/settings.py:315 sith/settings_sample.py:314 +#: sith/settings.py:316 sith/settings_sample.py:316 msgid "Secretary" msgstr "Secrétaire" -#: sith/settings.py:316 sith/settings_sample.py:315 +#: sith/settings.py:317 sith/settings_sample.py:317 msgid "IT supervisor" msgstr "Responsable info" -#: sith/settings.py:317 sith/settings_sample.py:316 +#: sith/settings.py:318 sith/settings_sample.py:318 msgid "Board member" msgstr "Membre du bureau" -#: sith/settings.py:318 sith/settings_sample.py:317 +#: sith/settings.py:319 sith/settings_sample.py:319 msgid "Active member" msgstr "Membre actif" -#: sith/settings.py:319 sith/settings_sample.py:318 +#: sith/settings.py:320 sith/settings_sample.py:320 msgid "Curious" msgstr "Curieux" @@ -1520,5 +1565,5 @@ msgstr "Un utilisateur avec cette adresse email existe déjà" #: subscription/views.py:57 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." - +msgstr "" +"Vous devez soit choisir un utilisateur existant, ou en créer un proprement."