mirror of
				https://github.com/ae-utbm/sith.git
				synced 2025-11-03 18:43:04 +00:00 
			
		
		
		
	Merge pull request #921 from ae-utbm/counter-click
Casser counter click étape 1 : introduire des fragments
This commit is contained in:
		@@ -1,3 +1,11 @@
 | 
				
			|||||||
import htmx from "htmx.org";
 | 
					import htmx from "htmx.org";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.body.addEventListener("htmx:beforeRequest", (event) => {
 | 
				
			||||||
 | 
					  event.target.ariaBusy = true;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.body.addEventListener("htmx:afterRequest", (event) => {
 | 
				
			||||||
 | 
					  event.originalTarget.ariaBusy = null;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Object.assign(window, { htmx });
 | 
					Object.assign(window, { htmx });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,16 @@
 | 
				
			|||||||
 **/
 | 
					 **/
 | 
				
			||||||
export function registerComponent(name: string, options?: ElementDefinitionOptions) {
 | 
					export function registerComponent(name: string, options?: ElementDefinitionOptions) {
 | 
				
			||||||
  return (component: CustomElementConstructor) => {
 | 
					  return (component: CustomElementConstructor) => {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
      window.customElements.define(name, component, options);
 | 
					      window.customElements.define(name, component, options);
 | 
				
			||||||
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      if (e instanceof DOMException) {
 | 
				
			||||||
 | 
					        // biome-ignore lint/suspicious/noConsole: it's handy to troobleshot
 | 
				
			||||||
 | 
					        console.warn(e.message);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      throw e;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,35 +35,12 @@
 | 
				
			|||||||
    {% endif %}
 | 
					    {% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {% if profile.customer %}
 | 
					    {% if student_card %}
 | 
				
			||||||
      <h3>{% trans %}Student cards{% endtrans %}</h3>
 | 
					      {{ student_card }}
 | 
				
			||||||
 | 
					 | 
				
			||||||
      {% if profile.customer.student_cards.exists() %}
 | 
					 | 
				
			||||||
        <ul class="student-cards">
 | 
					 | 
				
			||||||
          {% for card in profile.customer.student_cards.all() %}
 | 
					 | 
				
			||||||
            <li>
 | 
					 | 
				
			||||||
              {{ card.uid }}
 | 
					 | 
				
			||||||
               - 
 | 
					 | 
				
			||||||
              <a href="{{ url('counter:delete_student_card', customer_id=profile.customer.pk, card_id=card.id) }}">
 | 
					 | 
				
			||||||
                {% trans %}Delete{% endtrans %}
 | 
					 | 
				
			||||||
              </a>
 | 
					 | 
				
			||||||
            </li>
 | 
					 | 
				
			||||||
          {% endfor %}
 | 
					 | 
				
			||||||
        </ul>
 | 
					 | 
				
			||||||
      {% else %}
 | 
					 | 
				
			||||||
        <em class="no-cards">{% trans %}No student card registered.{% endtrans %}</em>
 | 
					 | 
				
			||||||
      <p class="justify">
 | 
					      <p class="justify">
 | 
				
			||||||
        {% trans %}You can add a card by asking at a counter or add it yourself here. If you want to manually
 | 
					        {% trans %}You can add a card by asking at a counter or add it yourself here. If you want to manually
 | 
				
			||||||
          add a student card yourself, you'll need a NFC reader. We store the UID of the card which is 14 characters long.{% endtrans %}
 | 
					          add a student card yourself, you'll need a NFC reader. We store the UID of the card which is 14 characters long.{% endtrans %}
 | 
				
			||||||
      </p>
 | 
					      </p>
 | 
				
			||||||
    {% endif %}
 | 
					    {% endif %}
 | 
				
			||||||
 | 
					 | 
				
			||||||
      <form class="form form-cards" action="{{ url('counter:add_student_card', customer_id=profile.customer.pk) }}"
 | 
					 | 
				
			||||||
            method="post">
 | 
					 | 
				
			||||||
        {% csrf_token %}
 | 
					 | 
				
			||||||
        {{ student_card_form.as_p() }}
 | 
					 | 
				
			||||||
        <input class="form-submit-btn" type="submit" value="{% trans %}Save{% endtrans %}" />
 | 
					 | 
				
			||||||
      </form>
 | 
					 | 
				
			||||||
    {% endif %}
 | 
					 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
@@ -13,22 +13,41 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from dataclasses import dataclass
 | 
				
			||||||
from datetime import date
 | 
					from datetime import date
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Image utils
 | 
					# Image utils
 | 
				
			||||||
from io import BytesIO
 | 
					from io import BytesIO
 | 
				
			||||||
from typing import Optional
 | 
					from typing import Any
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import PIL
 | 
					import PIL
 | 
				
			||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
from django.core.files.base import ContentFile
 | 
					from django.core.files.base import ContentFile
 | 
				
			||||||
 | 
					from django.forms import BaseForm
 | 
				
			||||||
from django.http import HttpRequest
 | 
					from django.http import HttpRequest
 | 
				
			||||||
 | 
					from django.template.loader import render_to_string
 | 
				
			||||||
 | 
					from django.utils.html import SafeString
 | 
				
			||||||
from django.utils.timezone import localdate
 | 
					from django.utils.timezone import localdate
 | 
				
			||||||
from PIL import ExifTags
 | 
					from PIL import ExifTags
 | 
				
			||||||
from PIL.Image import Image, Resampling
 | 
					from PIL.Image import Image, Resampling
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_start_of_semester(today: Optional[date] = None) -> date:
 | 
					@dataclass
 | 
				
			||||||
 | 
					class FormFragmentTemplateData[T: BaseForm]:
 | 
				
			||||||
 | 
					    """Dataclass used to pre-render form fragments"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    form: T
 | 
				
			||||||
 | 
					    template: str
 | 
				
			||||||
 | 
					    context: dict[str, Any]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def render(self, request: HttpRequest) -> SafeString:
 | 
				
			||||||
 | 
					        # Request is needed for csrf_tokens
 | 
				
			||||||
 | 
					        return render_to_string(
 | 
				
			||||||
 | 
					            self.template, context={"form": self.form, **self.context}, request=request
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_start_of_semester(today: date | None = None) -> date:
 | 
				
			||||||
    """Return the date of the start of the semester of the given date.
 | 
					    """Return the date of the start of the semester of the given date.
 | 
				
			||||||
    If no date is given, return the start date of the current semester.
 | 
					    If no date is given, return the start date of the current semester.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -58,7 +77,7 @@ def get_start_of_semester(today: Optional[date] = None) -> date:
 | 
				
			|||||||
    return autumn.replace(year=autumn.year - 1)
 | 
					    return autumn.replace(year=autumn.year - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_semester_code(d: Optional[date] = None) -> str:
 | 
					def get_semester_code(d: date | None = None) -> str:
 | 
				
			||||||
    """Return the semester code of the given date.
 | 
					    """Return the semester code of the given date.
 | 
				
			||||||
    If no date is given, return the semester code of the current semester.
 | 
					    If no date is given, return the semester code of the current semester.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -70,8 +70,8 @@ from core.views.forms import (
 | 
				
			|||||||
    UserGodfathersForm,
 | 
					    UserGodfathersForm,
 | 
				
			||||||
    UserProfileForm,
 | 
					    UserProfileForm,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from counter.forms import StudentCardForm
 | 
					 | 
				
			||||||
from counter.models import Refilling, Selling
 | 
					from counter.models import Refilling, Selling
 | 
				
			||||||
 | 
					from counter.views.student_card import StudentCardFormView
 | 
				
			||||||
from eboutic.models import Invoice
 | 
					from eboutic.models import Invoice
 | 
				
			||||||
from subscription.models import Subscription
 | 
					from subscription.models import Subscription
 | 
				
			||||||
from trombi.views import UserTrombiForm
 | 
					from trombi.views import UserTrombiForm
 | 
				
			||||||
@@ -576,9 +576,10 @@ class UserPreferencesView(UserTabsMixin, CanEditMixin, UpdateView):
 | 
				
			|||||||
            hasattr(self.object, "trombi_user") and self.request.user.trombi_user.trombi
 | 
					            hasattr(self.object, "trombi_user") and self.request.user.trombi_user.trombi
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            kwargs["trombi_form"] = UserTrombiForm()
 | 
					            kwargs["trombi_form"] = UserTrombiForm()
 | 
				
			||||||
 | 
					 | 
				
			||||||
        if hasattr(self.object, "customer"):
 | 
					        if hasattr(self.object, "customer"):
 | 
				
			||||||
            kwargs["student_card_form"] = StudentCardForm()
 | 
					            kwargs["student_card"] = StudentCardFormView.get_template_data(
 | 
				
			||||||
 | 
					                self.object.customer
 | 
				
			||||||
 | 
					            ).render(self.request)
 | 
				
			||||||
        return kwargs
 | 
					        return kwargs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,9 +45,7 @@ class BillingInfoForm(forms.ModelForm):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class StudentCardForm(forms.ModelForm):
 | 
					class StudentCardForm(forms.ModelForm):
 | 
				
			||||||
    """Form for adding student cards
 | 
					    """Form for adding student cards"""
 | 
				
			||||||
    Only used for user profile since CounterClick is to complicated.
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = StudentCard
 | 
					        model = StudentCard
 | 
				
			||||||
@@ -114,14 +112,6 @@ class GetUserForm(forms.Form):
 | 
				
			|||||||
        return cleaned_data
 | 
					        return cleaned_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NFCCardForm(forms.Form):
 | 
					 | 
				
			||||||
    student_card_uid = forms.CharField(
 | 
					 | 
				
			||||||
        max_length=StudentCard.UID_SIZE,
 | 
					 | 
				
			||||||
        required=False,
 | 
					 | 
				
			||||||
        widget=NFCTextInput,
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class RefillForm(forms.ModelForm):
 | 
					class RefillForm(forms.ModelForm):
 | 
				
			||||||
    error_css_class = "error"
 | 
					    error_css_class = "error"
 | 
				
			||||||
    required_css_class = "required"
 | 
					    required_css_class = "required"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,26 +29,9 @@
 | 
				
			|||||||
      {{ user_mini_profile(customer.user) }}
 | 
					      {{ user_mini_profile(customer.user) }}
 | 
				
			||||||
      {{ user_subscription(customer.user) }}
 | 
					      {{ user_subscription(customer.user) }}
 | 
				
			||||||
      <p>{% trans %}Amount: {% endtrans %}{{ customer.amount }} €</p>
 | 
					      <p>{% trans %}Amount: {% endtrans %}{{ customer.amount }} €</p>
 | 
				
			||||||
      <form method="post" action="{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}">
 | 
					 | 
				
			||||||
        {% csrf_token %}
 | 
					 | 
				
			||||||
        <input type="hidden" name="action" value="add_student_card">
 | 
					 | 
				
			||||||
        {% trans %}Add a student card{% endtrans %}
 | 
					 | 
				
			||||||
        {{  student_card_input.student_card_uid }}
 | 
					 | 
				
			||||||
        {% if request.session['not_valid_student_card_uid'] %}
 | 
					 | 
				
			||||||
          <p><strong>{% trans %}This is not a valid student card UID{% endtrans %}</strong></p>
 | 
					 | 
				
			||||||
        {% endif %}
 | 
					 | 
				
			||||||
        <input type="submit" value="{% trans %}Go{% endtrans %}"/>
 | 
					 | 
				
			||||||
      </form>
 | 
					 | 
				
			||||||
      <h6>{% trans %}Registered cards{% endtrans %}</h6>
 | 
					 | 
				
			||||||
      {% if student_cards %}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <ul>
 | 
					      {% if counter.type == 'BAR' %}
 | 
				
			||||||
          {% for card in student_cards %}
 | 
					        {{ student_card }}
 | 
				
			||||||
            <li>{{ card.uid }}</li>
 | 
					 | 
				
			||||||
          {% endfor %}
 | 
					 | 
				
			||||||
        </ul>
 | 
					 | 
				
			||||||
      {% else %}
 | 
					 | 
				
			||||||
        {% trans %}No card registered{% endtrans %}
 | 
					 | 
				
			||||||
      {% endif %}
 | 
					      {% endif %}
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					<div id="student_card_form">
 | 
				
			||||||
 | 
					  <h3>{% trans %}Add a student card{% endtrans %}</h3>
 | 
				
			||||||
 | 
					  <form
 | 
				
			||||||
 | 
					    hx-post="{{ action }}"
 | 
				
			||||||
 | 
					    hx-swap="outerHTML"
 | 
				
			||||||
 | 
					    hx-target="#student_card_form"
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
 | 
					    {% csrf_token %}
 | 
				
			||||||
 | 
					    {{  form.as_p() }}
 | 
				
			||||||
 | 
					    <input type="submit" value="{% trans %}Go{% endtrans %}"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  </form>
 | 
				
			||||||
 | 
					  <h6>{% trans %}Registered cards{% endtrans %}</h6>
 | 
				
			||||||
 | 
					  {% if student_cards %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <ul>
 | 
				
			||||||
 | 
					      {% for card in student_cards %}
 | 
				
			||||||
 | 
					        <li>
 | 
				
			||||||
 | 
					          {{ card.uid }}
 | 
				
			||||||
 | 
					          <a href="{{ url('counter:delete_student_card', customer_id=customer.pk, card_id=card.id) }}">
 | 
				
			||||||
 | 
					            {% trans %}Delete{% endtrans %}
 | 
				
			||||||
 | 
					          </a>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					      {% endfor %}
 | 
				
			||||||
 | 
					    </ul>
 | 
				
			||||||
 | 
					  {% else %}
 | 
				
			||||||
 | 
					    <em class="no-cards">{% trans %}No student card registered.{% endtrans %}</em>
 | 
				
			||||||
 | 
					  {% endif %}
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
@@ -1,15 +1,27 @@
 | 
				
			|||||||
import json
 | 
					import json
 | 
				
			||||||
import string
 | 
					import string
 | 
				
			||||||
 | 
					from datetime import timedelta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
 | 
					from django.conf import settings
 | 
				
			||||||
 | 
					from django.contrib.auth.base_user import make_password
 | 
				
			||||||
from django.test import Client, TestCase
 | 
					from django.test import Client, TestCase
 | 
				
			||||||
from django.urls import reverse
 | 
					from django.urls import reverse
 | 
				
			||||||
 | 
					from django.utils.timezone import now
 | 
				
			||||||
from model_bakery import baker
 | 
					from model_bakery import baker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from core.baker_recipes import subscriber_user
 | 
					from club.models import Membership
 | 
				
			||||||
 | 
					from core.baker_recipes import board_user, subscriber_user
 | 
				
			||||||
from core.models import User
 | 
					from core.models import User
 | 
				
			||||||
from counter.baker_recipes import refill_recipe, sale_recipe
 | 
					from counter.baker_recipes import refill_recipe, sale_recipe
 | 
				
			||||||
from counter.models import BillingInfo, Counter, Customer, Refilling, Selling
 | 
					from counter.models import (
 | 
				
			||||||
 | 
					    BillingInfo,
 | 
				
			||||||
 | 
					    Counter,
 | 
				
			||||||
 | 
					    Customer,
 | 
				
			||||||
 | 
					    Refilling,
 | 
				
			||||||
 | 
					    Selling,
 | 
				
			||||||
 | 
					    StudentCard,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.django_db
 | 
					@pytest.mark.django_db
 | 
				
			||||||
@@ -162,148 +174,269 @@ class TestStudentCard(TestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def setUpTestData(cls):
 | 
					    def setUpTestData(cls):
 | 
				
			||||||
        cls.krophil = User.objects.get(username="krophil")
 | 
					        cls.customer = subscriber_user.make()
 | 
				
			||||||
        cls.sli = User.objects.get(username="sli")
 | 
					        cls.customer.save()
 | 
				
			||||||
        cls.skia = User.objects.get(username="skia")
 | 
					        cls.barmen = subscriber_user.make(password=make_password("plop"))
 | 
				
			||||||
        cls.root = User.objects.get(username="root")
 | 
					        cls.board_admin = board_user.make()
 | 
				
			||||||
 | 
					        cls.club_admin = baker.make(User)
 | 
				
			||||||
 | 
					        cls.root = baker.make(User, is_superuser=True)
 | 
				
			||||||
 | 
					        cls.subscriber = subscriber_user.make()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        cls.counter = Counter.objects.get(id=2)
 | 
					        cls.counter = baker.make(Counter, type="BAR")
 | 
				
			||||||
 | 
					        cls.counter.sellers.add(cls.barmen)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cls.club_counter = baker.make(Counter)
 | 
				
			||||||
 | 
					        baker.make(
 | 
				
			||||||
 | 
					            Membership,
 | 
				
			||||||
 | 
					            start_date=now() - timedelta(days=30),
 | 
				
			||||||
 | 
					            club=cls.club_counter.club,
 | 
				
			||||||
 | 
					            role=settings.SITH_CLUB_ROLES_ID["Board member"],
 | 
				
			||||||
 | 
					            user=cls.club_admin,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cls.valid_card = baker.make(
 | 
				
			||||||
 | 
					            StudentCard, customer=cls.customer.customer, uid="8A89B82018B0A0"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        # Auto login on counter
 | 
					        # Auto login on counter
 | 
				
			||||||
        self.client.post(
 | 
					        self.client.post(
 | 
				
			||||||
            reverse("counter:login", args=[self.counter.id]),
 | 
					            reverse("counter:login", args=[self.counter.id]),
 | 
				
			||||||
            {"username": "krophil", "password": "plop"},
 | 
					            {"username": self.barmen.username, "password": "plop"},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_search_user_with_student_card(self):
 | 
					    def test_search_user_with_student_card(self):
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse("counter:details", args=[self.counter.id]),
 | 
					            reverse("counter:details", args=[self.counter.id]),
 | 
				
			||||||
            {"code": "9A89B82018B0A0"},
 | 
					            {"code": self.valid_card.uid},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert response.url == reverse(
 | 
					        assert response.url == reverse(
 | 
				
			||||||
            "counter:click",
 | 
					            "counter:click",
 | 
				
			||||||
            kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
 | 
					            kwargs={"counter_id": self.counter.id, "user_id": self.customer.id},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_add_student_card_from_counter(self):
 | 
					    def test_add_student_card_from_counter(self):
 | 
				
			||||||
        # Test card with mixed letters and numbers
 | 
					        # Test card with mixed letters and numbers
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:click",
 | 
					                "counter:add_student_card",
 | 
				
			||||||
                kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
 | 
					                kwargs={
 | 
				
			||||||
 | 
					                    "customer_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            {"uid": "8B90734A802A8F"},
 | 
				
			||||||
 | 
					            HTTP_REFERER=reverse(
 | 
				
			||||||
 | 
					                "counter:click",
 | 
				
			||||||
 | 
					                kwargs={
 | 
				
			||||||
 | 
					                    "counter_id": self.counter.id,
 | 
				
			||||||
 | 
					                    "user_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"student_card_uid": "8B90734A802A8F", "action": "add_student_card"},
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        self.assertContains(response, text="8B90734A802A8F")
 | 
					        assert response.status_code == 302
 | 
				
			||||||
 | 
					        self.assertContains(self.client.get(response.url), text="8B90734A802A8F")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Test card with only numbers
 | 
					        # Test card with only numbers
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:click",
 | 
					                "counter:add_student_card",
 | 
				
			||||||
                kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
 | 
					                kwargs={
 | 
				
			||||||
 | 
					                    "customer_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            {"uid": "04786547890123"},
 | 
				
			||||||
 | 
					            HTTP_REFERER=reverse(
 | 
				
			||||||
 | 
					                "counter:click",
 | 
				
			||||||
 | 
					                kwargs={
 | 
				
			||||||
 | 
					                    "counter_id": self.counter.id,
 | 
				
			||||||
 | 
					                    "user_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"student_card_uid": "04786547890123", "action": "add_student_card"},
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        self.assertContains(response, text="04786547890123")
 | 
					        assert response.status_code == 302
 | 
				
			||||||
 | 
					        self.assertContains(self.client.get(response.url), text="04786547890123")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Test card with only letters
 | 
					        # Test card with only letters
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:click",
 | 
					                "counter:add_student_card",
 | 
				
			||||||
                kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
 | 
					                kwargs={
 | 
				
			||||||
 | 
					                    "customer_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            {"uid": "ABCAAAFAAFAAAB"},
 | 
				
			||||||
 | 
					            HTTP_REFERER=reverse(
 | 
				
			||||||
 | 
					                "counter:click",
 | 
				
			||||||
 | 
					                kwargs={
 | 
				
			||||||
 | 
					                    "counter_id": self.counter.id,
 | 
				
			||||||
 | 
					                    "user_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"student_card_uid": "ABCAAAFAAFAAAB", "action": "add_student_card"},
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        self.assertContains(response, text="ABCAAAFAAFAAAB")
 | 
					        assert response.status_code == 302
 | 
				
			||||||
 | 
					        self.assertContains(self.client.get(response.url), text="ABCAAAFAAFAAAB")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_add_student_card_from_counter_fail(self):
 | 
					    def test_add_student_card_from_counter_fail(self):
 | 
				
			||||||
        # UID too short
 | 
					        # UID too short
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:click",
 | 
					                "counter:add_student_card",
 | 
				
			||||||
                kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
 | 
					                kwargs={
 | 
				
			||||||
 | 
					                    "customer_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            {"uid": "8B90734A802A8"},
 | 
				
			||||||
 | 
					            HTTP_REFERER=reverse(
 | 
				
			||||||
 | 
					                "counter:click",
 | 
				
			||||||
 | 
					                kwargs={
 | 
				
			||||||
 | 
					                    "counter_id": self.counter.id,
 | 
				
			||||||
 | 
					                    "user_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"student_card_uid": "8B90734A802A8", "action": "add_student_card"},
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        self.assertContains(
 | 
					 | 
				
			||||||
            response, text="Ce n'est pas un UID de carte étudiante valide"
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertContains(response, text="Cet UID est invalide")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # UID too long
 | 
					        # UID too long
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:click",
 | 
					                "counter:add_student_card",
 | 
				
			||||||
                kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
 | 
					                kwargs={
 | 
				
			||||||
 | 
					                    "customer_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            {"uid": "8B90734A802A8FA"},
 | 
				
			||||||
 | 
					            HTTP_REFERER=reverse(
 | 
				
			||||||
 | 
					                "counter:click",
 | 
				
			||||||
 | 
					                kwargs={
 | 
				
			||||||
 | 
					                    "counter_id": self.counter.id,
 | 
				
			||||||
 | 
					                    "user_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"student_card_uid": "8B90734A802A8FA", "action": "add_student_card"},
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertContains(response, text="Cet UID est invalide")
 | 
				
			||||||
        self.assertContains(
 | 
					        self.assertContains(
 | 
				
			||||||
            response, text="Ce n'est pas un UID de carte étudiante valide"
 | 
					            response,
 | 
				
			||||||
 | 
					            text="Assurez-vous que cette valeur comporte au plus 14 caractères (actuellement 15).",
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Test with already existing card
 | 
					        # Test with already existing card
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:click",
 | 
					                "counter:add_student_card",
 | 
				
			||||||
                kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
 | 
					                kwargs={
 | 
				
			||||||
 | 
					                    "customer_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            {"uid": self.valid_card.uid},
 | 
				
			||||||
 | 
					            HTTP_REFERER=reverse(
 | 
				
			||||||
 | 
					                "counter:click",
 | 
				
			||||||
 | 
					                kwargs={
 | 
				
			||||||
 | 
					                    "counter_id": self.counter.id,
 | 
				
			||||||
 | 
					                    "user_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"student_card_uid": "9A89B82018B0A0", "action": "add_student_card"},
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertContains(response, text="Cet UID est invalide")
 | 
				
			||||||
        self.assertContains(
 | 
					        self.assertContains(
 | 
				
			||||||
            response, text="Ce n'est pas un UID de carte étudiante valide"
 | 
					            response, text="Un objet Student card avec ce champ Uid existe déjà."
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Test with lowercase
 | 
					        # Test with lowercase
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:click",
 | 
					                "counter:add_student_card",
 | 
				
			||||||
                kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
 | 
					                kwargs={
 | 
				
			||||||
 | 
					                    "customer_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            {"uid": "8b90734a802a9f"},
 | 
				
			||||||
 | 
					            HTTP_REFERER=reverse(
 | 
				
			||||||
 | 
					                "counter:click",
 | 
				
			||||||
 | 
					                kwargs={
 | 
				
			||||||
 | 
					                    "counter_id": self.counter.id,
 | 
				
			||||||
 | 
					                    "user_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"student_card_uid": "8b90734a802a9f", "action": "add_student_card"},
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        self.assertContains(
 | 
					 | 
				
			||||||
            response, text="Ce n'est pas un UID de carte étudiante valide"
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertContains(response, text="Cet UID est invalide")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Test with white spaces
 | 
					        # Test with white spaces
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:click",
 | 
					                "counter:add_student_card",
 | 
				
			||||||
                kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
 | 
					                kwargs={
 | 
				
			||||||
 | 
					                    "customer_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            {"uid": "              "},
 | 
				
			||||||
 | 
					            HTTP_REFERER=reverse(
 | 
				
			||||||
 | 
					                "counter:click",
 | 
				
			||||||
 | 
					                kwargs={
 | 
				
			||||||
 | 
					                    "counter_id": self.counter.id,
 | 
				
			||||||
 | 
					                    "user_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"student_card_uid": "              ", "action": "add_student_card"},
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        self.assertContains(
 | 
					        self.assertContains(response, text="Cet UID est invalide")
 | 
				
			||||||
            response, text="Ce n'est pas un UID de carte étudiante valide"
 | 
					        self.assertContains(response, text="Ce champ est obligatoire.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_add_student_card_from_counter_unauthorized(self):
 | 
				
			||||||
 | 
					        # Send to a counter where you aren't logged in
 | 
				
			||||||
 | 
					        self.client.post(
 | 
				
			||||||
 | 
					            reverse("counter:logout", args=[self.counter.id]),
 | 
				
			||||||
 | 
					            {"user_id": self.barmen.id},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def send_valid_request(client, counter_id):
 | 
				
			||||||
 | 
					            return client.post(
 | 
				
			||||||
 | 
					                reverse(
 | 
				
			||||||
 | 
					                    "counter:add_student_card",
 | 
				
			||||||
 | 
					                    kwargs={
 | 
				
			||||||
 | 
					                        "customer_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                {"uid": "8B90734A802A8F"},
 | 
				
			||||||
 | 
					                HTTP_REFERER=reverse(
 | 
				
			||||||
 | 
					                    "counter:click",
 | 
				
			||||||
 | 
					                    kwargs={
 | 
				
			||||||
 | 
					                        "counter_id": counter_id,
 | 
				
			||||||
 | 
					                        "user_id": self.customer.customer.pk,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert send_valid_request(self.client, self.counter.id).status_code == 403
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Send to a non bar counter
 | 
				
			||||||
 | 
					        self.client.force_login(self.club_admin)
 | 
				
			||||||
 | 
					        assert send_valid_request(self.client, self.club_counter.id).status_code == 403
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_delete_student_card_with_owner(self):
 | 
					    def test_delete_student_card_with_owner(self):
 | 
				
			||||||
        self.client.force_login(self.sli)
 | 
					        self.client.force_login(self.customer)
 | 
				
			||||||
        self.client.post(
 | 
					        self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:delete_student_card",
 | 
					                "counter:delete_student_card",
 | 
				
			||||||
                kwargs={
 | 
					                kwargs={
 | 
				
			||||||
                    "customer_id": self.sli.customer.pk,
 | 
					                    "customer_id": self.customer.customer.pk,
 | 
				
			||||||
                    "card_id": self.sli.customer.student_cards.first().id,
 | 
					                    "card_id": self.customer.customer.student_cards.first().id,
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        assert not self.sli.customer.student_cards.exists()
 | 
					        assert not self.customer.customer.student_cards.exists()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_delete_student_card_with_board_member(self):
 | 
					    def test_delete_student_card_with_board_member(self):
 | 
				
			||||||
        self.client.force_login(self.skia)
 | 
					        self.client.force_login(self.board_admin)
 | 
				
			||||||
        self.client.post(
 | 
					        self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:delete_student_card",
 | 
					                "counter:delete_student_card",
 | 
				
			||||||
                kwargs={
 | 
					                kwargs={
 | 
				
			||||||
                    "customer_id": self.sli.customer.pk,
 | 
					                    "customer_id": self.customer.customer.pk,
 | 
				
			||||||
                    "card_id": self.sli.customer.student_cards.first().id,
 | 
					                    "card_id": self.customer.customer.student_cards.first().id,
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        assert not self.sli.customer.student_cards.exists()
 | 
					        assert not self.customer.customer.student_cards.exists()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_delete_student_card_with_root(self):
 | 
					    def test_delete_student_card_with_root(self):
 | 
				
			||||||
        self.client.force_login(self.root)
 | 
					        self.client.force_login(self.root)
 | 
				
			||||||
@@ -311,100 +444,107 @@ class TestStudentCard(TestCase):
 | 
				
			|||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:delete_student_card",
 | 
					                "counter:delete_student_card",
 | 
				
			||||||
                kwargs={
 | 
					                kwargs={
 | 
				
			||||||
                    "customer_id": self.sli.customer.pk,
 | 
					                    "customer_id": self.customer.customer.pk,
 | 
				
			||||||
                    "card_id": self.sli.customer.student_cards.first().id,
 | 
					                    "card_id": self.customer.customer.student_cards.first().id,
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        assert not self.sli.customer.student_cards.exists()
 | 
					        assert not self.customer.customer.student_cards.exists()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_delete_student_card_fail(self):
 | 
					    def test_delete_student_card_fail(self):
 | 
				
			||||||
        self.client.force_login(self.krophil)
 | 
					        self.client.force_login(self.subscriber)
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:delete_student_card",
 | 
					                "counter:delete_student_card",
 | 
				
			||||||
                kwargs={
 | 
					                kwargs={
 | 
				
			||||||
                    "customer_id": self.sli.customer.pk,
 | 
					                    "customer_id": self.customer.customer.pk,
 | 
				
			||||||
                    "card_id": self.sli.customer.student_cards.first().id,
 | 
					                    "card_id": self.customer.customer.student_cards.first().id,
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        assert response.status_code == 403
 | 
					        assert response.status_code == 403
 | 
				
			||||||
        assert self.sli.customer.student_cards.exists()
 | 
					        assert self.customer.customer.student_cards.exists()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_add_student_card_from_user_preferences(self):
 | 
					    def test_add_student_card_from_user_preferences(self):
 | 
				
			||||||
        # Test with owner of the card
 | 
					        # Test with owner of the card
 | 
				
			||||||
        self.client.force_login(self.sli)
 | 
					        self.client.force_login(self.customer)
 | 
				
			||||||
        self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
 | 
					                "counter:add_student_card",
 | 
				
			||||||
 | 
					                kwargs={"customer_id": self.customer.customer.pk},
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"uid": "8B90734A802A8F"},
 | 
					            {"uid": "8B90734A802A8F"},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        response = self.client.get(
 | 
					        assert response.status_code == 302
 | 
				
			||||||
            reverse("core:user_prefs", kwargs={"user_id": self.sli.id})
 | 
					
 | 
				
			||||||
        )
 | 
					        response = self.client.get(response.url)
 | 
				
			||||||
        self.assertContains(response, text="8B90734A802A8F")
 | 
					        self.assertContains(response, text="8B90734A802A8F")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Test with board member
 | 
					        # Test with board member
 | 
				
			||||||
        self.client.force_login(self.skia)
 | 
					        self.client.force_login(self.board_admin)
 | 
				
			||||||
        self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
 | 
					                "counter:add_student_card",
 | 
				
			||||||
 | 
					                kwargs={"customer_id": self.customer.customer.pk},
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"uid": "8B90734A802A8A"},
 | 
					            {"uid": "8B90734A802A8A"},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        response = self.client.get(
 | 
					        assert response.status_code == 302
 | 
				
			||||||
            reverse("core:user_prefs", kwargs={"user_id": self.sli.id})
 | 
					
 | 
				
			||||||
        )
 | 
					        response = self.client.get(response.url)
 | 
				
			||||||
        self.assertContains(response, text="8B90734A802A8A")
 | 
					        self.assertContains(response, text="8B90734A802A8A")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Test card with only numbers
 | 
					        # Test card with only numbers
 | 
				
			||||||
        self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
 | 
					                "counter:add_student_card",
 | 
				
			||||||
 | 
					                kwargs={"customer_id": self.customer.customer.pk},
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"uid": "04786547890123"},
 | 
					            {"uid": "04786547890123"},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        response = self.client.get(
 | 
					        assert response.status_code == 302
 | 
				
			||||||
            reverse("core:user_prefs", kwargs={"user_id": self.sli.id})
 | 
					
 | 
				
			||||||
        )
 | 
					        response = self.client.get(response.url)
 | 
				
			||||||
        self.assertContains(response, text="04786547890123")
 | 
					        self.assertContains(response, text="04786547890123")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Test card with only letters
 | 
					        # Test card with only letters
 | 
				
			||||||
        self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
 | 
					                "counter:add_student_card",
 | 
				
			||||||
 | 
					                kwargs={"customer_id": self.customer.customer.pk},
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"uid": "ABCAAAFAAFAAAB"},
 | 
					            {"uid": "ABCAAAFAAFAAAB"},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        response = self.client.get(
 | 
					
 | 
				
			||||||
            reverse("core:user_prefs", kwargs={"user_id": self.sli.id})
 | 
					        assert response.status_code == 302
 | 
				
			||||||
        )
 | 
					
 | 
				
			||||||
 | 
					        response = self.client.get(response.url)
 | 
				
			||||||
        self.assertContains(response, text="ABCAAAFAAFAAAB")
 | 
					        self.assertContains(response, text="ABCAAAFAAFAAAB")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Test with root
 | 
					        # Test with root
 | 
				
			||||||
        self.client.force_login(self.root)
 | 
					        self.client.force_login(self.root)
 | 
				
			||||||
        self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
 | 
					                "counter:add_student_card",
 | 
				
			||||||
 | 
					                kwargs={"customer_id": self.customer.customer.pk},
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"uid": "8B90734A802A8B"},
 | 
					            {"uid": "8B90734A802A8B"},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        response = self.client.get(
 | 
					        assert response.status_code == 302
 | 
				
			||||||
            reverse("core:user_prefs", kwargs={"user_id": self.sli.id})
 | 
					
 | 
				
			||||||
        )
 | 
					        response = self.client.get(response.url)
 | 
				
			||||||
        self.assertContains(response, text="8B90734A802A8B")
 | 
					        self.assertContains(response, text="8B90734A802A8B")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_add_student_card_from_user_preferences_fail(self):
 | 
					    def test_add_student_card_from_user_preferences_fail(self):
 | 
				
			||||||
        self.client.force_login(self.sli)
 | 
					        self.client.force_login(self.customer)
 | 
				
			||||||
        # UID too short
 | 
					        # UID too short
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
 | 
					                "counter:add_student_card",
 | 
				
			||||||
 | 
					                kwargs={"customer_id": self.customer.customer.pk},
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"uid": "8B90734A802A8"},
 | 
					            {"uid": "8B90734A802A8"},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
@@ -414,7 +554,8 @@ class TestStudentCard(TestCase):
 | 
				
			|||||||
        # UID too long
 | 
					        # UID too long
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
 | 
					                "counter:add_student_card",
 | 
				
			||||||
 | 
					                kwargs={"customer_id": self.customer.customer.pk},
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"uid": "8B90734A802A8FA"},
 | 
					            {"uid": "8B90734A802A8FA"},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
@@ -423,9 +564,10 @@ class TestStudentCard(TestCase):
 | 
				
			|||||||
        # Test with already existing card
 | 
					        # Test with already existing card
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
 | 
					                "counter:add_student_card",
 | 
				
			||||||
 | 
					                kwargs={"customer_id": self.customer.customer.pk},
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"uid": "9A89B82018B0A0"},
 | 
					            {"uid": self.valid_card.uid},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        self.assertContains(
 | 
					        self.assertContains(
 | 
				
			||||||
            response, text="Un objet Student card avec ce champ Uid existe déjà."
 | 
					            response, text="Un objet Student card avec ce champ Uid existe déjà."
 | 
				
			||||||
@@ -434,7 +576,8 @@ class TestStudentCard(TestCase):
 | 
				
			|||||||
        # Test with lowercase
 | 
					        # Test with lowercase
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
 | 
					                "counter:add_student_card",
 | 
				
			||||||
 | 
					                kwargs={"customer_id": self.customer.customer.pk},
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"uid": "8b90734a802a9f"},
 | 
					            {"uid": "8b90734a802a9f"},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
@@ -443,17 +586,19 @@ class TestStudentCard(TestCase):
 | 
				
			|||||||
        # Test with white spaces
 | 
					        # Test with white spaces
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
 | 
					                "counter:add_student_card",
 | 
				
			||||||
 | 
					                kwargs={"customer_id": self.customer.customer.pk},
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"uid": " " * 14},
 | 
					            {"uid": " " * 14},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        self.assertContains(response, text="Cet UID est invalide")
 | 
					        self.assertContains(response, text="Cet UID est invalide")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Test with unauthorized user
 | 
					        # Test with unauthorized user
 | 
				
			||||||
        self.client.force_login(self.krophil)
 | 
					        self.client.force_login(self.subscriber)
 | 
				
			||||||
        response = self.client.post(
 | 
					        response = self.client.post(
 | 
				
			||||||
            reverse(
 | 
					            reverse(
 | 
				
			||||||
                "counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
 | 
					                "counter:add_student_card",
 | 
				
			||||||
 | 
					                kwargs={"customer_id": self.customer.customer.pk},
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            {"uid": "8B90734A802A8F"},
 | 
					            {"uid": "8B90734A802A8F"},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,7 +52,10 @@ from counter.views.home import (
 | 
				
			|||||||
    CounterMain,
 | 
					    CounterMain,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from counter.views.invoice import InvoiceCallView
 | 
					from counter.views.invoice import InvoiceCallView
 | 
				
			||||||
from counter.views.student_card import StudentCardDeleteView, StudentCardFormView
 | 
					from counter.views.student_card import (
 | 
				
			||||||
 | 
					    StudentCardDeleteView,
 | 
				
			||||||
 | 
					    StudentCardFormView,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
urlpatterns = [
 | 
					urlpatterns = [
 | 
				
			||||||
    path("<int:counter_id>/", CounterMain.as_view(), name="details"),
 | 
					    path("<int:counter_id>/", CounterMain.as_view(), name="details"),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,14 +22,22 @@ def is_logged_in_counter(request: HttpRequest) -> bool:
 | 
				
			|||||||
      to the counter)
 | 
					      to the counter)
 | 
				
			||||||
    - The current session has a counter token associated with it.
 | 
					    - The current session has a counter token associated with it.
 | 
				
			||||||
    - A counter with this token exists.
 | 
					    - A counter with this token exists.
 | 
				
			||||||
 | 
					    - The counter is open
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    referer_ok = (
 | 
					    referer_ok = (
 | 
				
			||||||
        "HTTP_REFERER" in request.META
 | 
					        "HTTP_REFERER" in request.META
 | 
				
			||||||
        and resolve(urlparse(request.META["HTTP_REFERER"]).path).app_name == "counter"
 | 
					        and resolve(urlparse(request.META["HTTP_REFERER"]).path).app_name == "counter"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    return (
 | 
					    has_token = (
 | 
				
			||||||
        (referer_ok or request.resolver_match.app_name == "counter")
 | 
					        (referer_ok or request.resolver_match.app_name == "counter")
 | 
				
			||||||
        and "counter_token" in request.session
 | 
					        and "counter_token" in request.session
 | 
				
			||||||
        and request.session["counter_token"]
 | 
					        and request.session["counter_token"]
 | 
				
			||||||
        and Counter.objects.filter(token=request.session["counter_token"]).exists()
 | 
					    )
 | 
				
			||||||
 | 
					    if not has_token:
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        Counter.objects.annotate_is_open()
 | 
				
			||||||
 | 
					        .filter(token=request.session["counter_token"], is_open=True)
 | 
				
			||||||
 | 
					        .exists()
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,9 +27,10 @@ from django.utils.translation import gettext_lazy as _
 | 
				
			|||||||
from django.views.generic import DetailView
 | 
					from django.views.generic import DetailView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from core.views import CanViewMixin
 | 
					from core.views import CanViewMixin
 | 
				
			||||||
from counter.forms import NFCCardForm, RefillForm
 | 
					from counter.forms import RefillForm
 | 
				
			||||||
from counter.models import Counter, Customer, Product, Selling, StudentCard
 | 
					from counter.models import Counter, Customer, Product, Selling
 | 
				
			||||||
from counter.views.mixins import CounterTabsMixin
 | 
					from counter.views.mixins import CounterTabsMixin
 | 
				
			||||||
 | 
					from counter.views.student_card import StudentCardFormView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if TYPE_CHECKING:
 | 
					if TYPE_CHECKING:
 | 
				
			||||||
    from core.models import User
 | 
					    from core.models import User
 | 
				
			||||||
@@ -134,7 +135,6 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView):
 | 
				
			|||||||
        request.session["too_young"] = False
 | 
					        request.session["too_young"] = False
 | 
				
			||||||
        request.session["not_allowed"] = False
 | 
					        request.session["not_allowed"] = False
 | 
				
			||||||
        request.session["no_age"] = False
 | 
					        request.session["no_age"] = False
 | 
				
			||||||
        request.session["not_valid_student_card_uid"] = False
 | 
					 | 
				
			||||||
        if self.object.type != "BAR":
 | 
					        if self.object.type != "BAR":
 | 
				
			||||||
            self.operator = request.user
 | 
					            self.operator = request.user
 | 
				
			||||||
        elif self.customer_is_barman():
 | 
					        elif self.customer_is_barman():
 | 
				
			||||||
@@ -146,8 +146,6 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView):
 | 
				
			|||||||
            action = parse_qs(request.body.decode()).get("action", [""])[0]
 | 
					            action = parse_qs(request.body.decode()).get("action", [""])[0]
 | 
				
			||||||
        if action == "add_product":
 | 
					        if action == "add_product":
 | 
				
			||||||
            self.add_product(request)
 | 
					            self.add_product(request)
 | 
				
			||||||
        elif action == "add_student_card":
 | 
					 | 
				
			||||||
            self.add_student_card(request)
 | 
					 | 
				
			||||||
        elif action == "del_product":
 | 
					        elif action == "del_product":
 | 
				
			||||||
            self.del_product(request)
 | 
					            self.del_product(request)
 | 
				
			||||||
        elif action == "refill":
 | 
					        elif action == "refill":
 | 
				
			||||||
@@ -284,23 +282,6 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView):
 | 
				
			|||||||
        request.session.modified = True
 | 
					        request.session.modified = True
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def add_student_card(self, request):
 | 
					 | 
				
			||||||
        """Add a new student card on the customer account."""
 | 
					 | 
				
			||||||
        uid = str(request.POST["student_card_uid"])
 | 
					 | 
				
			||||||
        if not StudentCard.is_valid(uid):
 | 
					 | 
				
			||||||
            request.session["not_valid_student_card_uid"] = True
 | 
					 | 
				
			||||||
            return False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if not (
 | 
					 | 
				
			||||||
            self.object.type == "BAR"
 | 
					 | 
				
			||||||
            and "counter_token" in request.session
 | 
					 | 
				
			||||||
            and request.session["counter_token"] == self.object.token
 | 
					 | 
				
			||||||
            and self.object.is_open
 | 
					 | 
				
			||||||
        ):
 | 
					 | 
				
			||||||
            raise PermissionDenied
 | 
					 | 
				
			||||||
        StudentCard(customer=self.customer, uid=uid).save()
 | 
					 | 
				
			||||||
        return True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def del_product(self, request):
 | 
					    def del_product(self, request):
 | 
				
			||||||
        """Delete a product from the basket."""
 | 
					        """Delete a product from the basket."""
 | 
				
			||||||
        pid = parse_qs(request.body.decode())["product_id"][0]
 | 
					        pid = parse_qs(request.body.decode())["product_id"][0]
 | 
				
			||||||
@@ -431,10 +412,10 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView):
 | 
				
			|||||||
                    product
 | 
					                    product
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
        kwargs["customer"] = self.customer
 | 
					        kwargs["customer"] = self.customer
 | 
				
			||||||
        kwargs["student_cards"] = self.customer.student_cards.all()
 | 
					 | 
				
			||||||
        kwargs["student_card_input"] = NFCCardForm()
 | 
					 | 
				
			||||||
        kwargs["basket_total"] = self.sum_basket(self.request)
 | 
					        kwargs["basket_total"] = self.sum_basket(self.request)
 | 
				
			||||||
        kwargs["refill_form"] = self.refill_form or RefillForm()
 | 
					        kwargs["refill_form"] = self.refill_form or RefillForm()
 | 
				
			||||||
        kwargs["student_card_max_uid_size"] = StudentCard.UID_SIZE
 | 
					 | 
				
			||||||
        kwargs["barmens_can_refill"] = self.object.can_refill()
 | 
					        kwargs["barmens_can_refill"] = self.object.can_refill()
 | 
				
			||||||
 | 
					        kwargs["student_card"] = StudentCardFormView.get_template_data(
 | 
				
			||||||
 | 
					            self.customer
 | 
				
			||||||
 | 
					        ).render(self.request)
 | 
				
			||||||
        return kwargs
 | 
					        return kwargs
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,14 +13,18 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.core.exceptions import PermissionDenied
 | 
					from django.core.exceptions import PermissionDenied
 | 
				
			||||||
 | 
					from django.http import HttpRequest
 | 
				
			||||||
from django.shortcuts import get_object_or_404
 | 
					from django.shortcuts import get_object_or_404
 | 
				
			||||||
from django.urls import reverse_lazy
 | 
					from django.urls import reverse_lazy
 | 
				
			||||||
from django.views.generic.edit import DeleteView, FormView
 | 
					from django.views.generic.edit import DeleteView, FormView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from core.utils import FormFragmentTemplateData
 | 
				
			||||||
from core.views import CanEditMixin
 | 
					from core.views import CanEditMixin
 | 
				
			||||||
from counter.forms import StudentCardForm
 | 
					from counter.forms import StudentCardForm
 | 
				
			||||||
from counter.models import Customer, StudentCard
 | 
					from counter.models import Customer, StudentCard
 | 
				
			||||||
 | 
					from counter.utils import is_logged_in_counter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class StudentCardDeleteView(DeleteView, CanEditMixin):
 | 
					class StudentCardDeleteView(DeleteView, CanEditMixin):
 | 
				
			||||||
@@ -41,15 +45,38 @@ class StudentCardDeleteView(DeleteView, CanEditMixin):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class StudentCardFormView(FormView):
 | 
					class StudentCardFormView(FormView):
 | 
				
			||||||
    """Add a new student card."""
 | 
					    """Add a new student card. This is a fragment view !"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    form_class = StudentCardForm
 | 
					    form_class = StudentCardForm
 | 
				
			||||||
    template_name = "core/create.jinja"
 | 
					    template_name = "counter/fragments/create_student_card.jinja"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def dispatch(self, request, *args, **kwargs):
 | 
					    @classmethod
 | 
				
			||||||
        self.customer = get_object_or_404(Customer, pk=kwargs["customer_id"])
 | 
					    def get_template_data(
 | 
				
			||||||
        if not StudentCard.can_create(self.customer, request.user):
 | 
					        cls, customer: Customer
 | 
				
			||||||
 | 
					    ) -> FormFragmentTemplateData[form_class]:
 | 
				
			||||||
 | 
					        """Get necessary data to pre-render the fragment"""
 | 
				
			||||||
 | 
					        return FormFragmentTemplateData[cls.form_class](
 | 
				
			||||||
 | 
					            form=cls.form_class(),
 | 
				
			||||||
 | 
					            template=cls.template_name,
 | 
				
			||||||
 | 
					            context={
 | 
				
			||||||
 | 
					                "action": reverse_lazy(
 | 
				
			||||||
 | 
					                    "counter:add_student_card", kwargs={"customer_id": customer.pk}
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                "customer": customer,
 | 
				
			||||||
 | 
					                "student_cards": customer.student_cards.all(),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dispatch(self, request: HttpRequest, *args, **kwargs):
 | 
				
			||||||
 | 
					        self.customer = get_object_or_404(
 | 
				
			||||||
 | 
					            Customer.objects.prefetch_related("student_cards"), pk=kwargs["customer_id"]
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not is_logged_in_counter(request) and not StudentCard.can_create(
 | 
				
			||||||
 | 
					            self.customer, request.user
 | 
				
			||||||
 | 
					        ):
 | 
				
			||||||
            raise PermissionDenied
 | 
					            raise PermissionDenied
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return super().dispatch(request, *args, **kwargs)
 | 
					        return super().dispatch(request, *args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def form_valid(self, form):
 | 
					    def form_valid(self, form):
 | 
				
			||||||
@@ -58,7 +85,11 @@ class StudentCardFormView(FormView):
 | 
				
			|||||||
        StudentCard(customer=self.customer, uid=data["uid"]).save()
 | 
					        StudentCard(customer=self.customer, uid=data["uid"]).save()
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
 | 
					        context = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					        data = self.get_template_data(self.customer)
 | 
				
			||||||
 | 
					        context.update(data.context)
 | 
				
			||||||
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_success_url(self, **kwargs):
 | 
					    def get_success_url(self, **kwargs):
 | 
				
			||||||
        return reverse_lazy(
 | 
					        return self.request.path
 | 
				
			||||||
            "core:user_prefs", kwargs={"user_id": self.customer.user.pk}
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Report-Msgid-Bugs-To: \n"
 | 
					"Report-Msgid-Bugs-To: \n"
 | 
				
			||||||
"POT-Creation-Date: 2024-11-29 18:04+0100\n"
 | 
					"POT-Creation-Date: 2024-12-08 00:29+0100\n"
 | 
				
			||||||
"PO-Revision-Date: 2016-07-18\n"
 | 
					"PO-Revision-Date: 2016-07-18\n"
 | 
				
			||||||
"Last-Translator: Maréchal <thomas.girod@utbm.fr\n"
 | 
					"Last-Translator: Maréchal <thomas.girod@utbm.fr\n"
 | 
				
			||||||
"Language-Team: AE info <ae.info@utbm.fr>\n"
 | 
					"Language-Team: AE info <ae.info@utbm.fr>\n"
 | 
				
			||||||
@@ -218,7 +218,7 @@ msgstr "Compte"
 | 
				
			|||||||
msgid "Company"
 | 
					msgid "Company"
 | 
				
			||||||
msgstr "Entreprise"
 | 
					msgstr "Entreprise"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: accounting/models.py:307 core/models.py:338 sith/settings.py:421
 | 
					#: accounting/models.py:307 core/models.py:338 sith/settings.py:423
 | 
				
			||||||
msgid "Other"
 | 
					msgid "Other"
 | 
				
			||||||
msgstr "Autre"
 | 
					msgstr "Autre"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -369,7 +369,7 @@ msgstr "Compte en banque : "
 | 
				
			|||||||
#: core/templates/core/user_clubs.jinja:34
 | 
					#: core/templates/core/user_clubs.jinja:34
 | 
				
			||||||
#: core/templates/core/user_clubs.jinja:63
 | 
					#: core/templates/core/user_clubs.jinja:63
 | 
				
			||||||
#: core/templates/core/user_edit.jinja:62
 | 
					#: core/templates/core/user_edit.jinja:62
 | 
				
			||||||
#: core/templates/core/user_preferences.jinja:48
 | 
					#: counter/templates/counter/fragments/create_student_card.jinja:21
 | 
				
			||||||
#: counter/templates/counter/last_ops.jinja:35
 | 
					#: counter/templates/counter/last_ops.jinja:35
 | 
				
			||||||
#: counter/templates/counter/last_ops.jinja:65
 | 
					#: counter/templates/counter/last_ops.jinja:65
 | 
				
			||||||
#: election/templates/election/election_detail.jinja:191
 | 
					#: election/templates/election/election_detail.jinja:191
 | 
				
			||||||
@@ -517,7 +517,7 @@ msgid "Effective amount"
 | 
				
			|||||||
msgstr "Montant effectif"
 | 
					msgstr "Montant effectif"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: accounting/templates/accounting/club_account_details.jinja:36
 | 
					#: accounting/templates/accounting/club_account_details.jinja:36
 | 
				
			||||||
#: sith/settings.py:467
 | 
					#: sith/settings.py:469
 | 
				
			||||||
msgid "Closed"
 | 
					msgid "Closed"
 | 
				
			||||||
msgstr "Fermé"
 | 
					msgstr "Fermé"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -650,8 +650,8 @@ msgid "Done"
 | 
				
			|||||||
msgstr "Effectuées"
 | 
					msgstr "Effectuées"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: accounting/templates/accounting/journal_details.jinja:41
 | 
					#: accounting/templates/accounting/journal_details.jinja:41
 | 
				
			||||||
#: counter/templates/counter/cash_summary_list.jinja:37 counter/views.py:955
 | 
					#: counter/templates/counter/cash_summary_list.jinja:37
 | 
				
			||||||
#: pedagogy/templates/pedagogy/moderation.jinja:13
 | 
					#: counter/views/cash.py:87 pedagogy/templates/pedagogy/moderation.jinja:13
 | 
				
			||||||
#: pedagogy/templates/pedagogy/uv_detail.jinja:142
 | 
					#: pedagogy/templates/pedagogy/uv_detail.jinja:142
 | 
				
			||||||
#: trombi/templates/trombi/comment.jinja:4
 | 
					#: trombi/templates/trombi/comment.jinja:4
 | 
				
			||||||
#: trombi/templates/trombi/comment.jinja:8
 | 
					#: trombi/templates/trombi/comment.jinja:8
 | 
				
			||||||
@@ -771,7 +771,6 @@ msgstr "Opération liée : "
 | 
				
			|||||||
#: core/templates/core/user_godfathers_tree.jinja:85
 | 
					#: core/templates/core/user_godfathers_tree.jinja:85
 | 
				
			||||||
#: core/templates/core/user_preferences.jinja:18
 | 
					#: core/templates/core/user_preferences.jinja:18
 | 
				
			||||||
#: core/templates/core/user_preferences.jinja:27
 | 
					#: core/templates/core/user_preferences.jinja:27
 | 
				
			||||||
#: core/templates/core/user_preferences.jinja:65
 | 
					 | 
				
			||||||
#: counter/templates/counter/cash_register_summary.jinja:28
 | 
					#: counter/templates/counter/cash_register_summary.jinja:28
 | 
				
			||||||
#: forum/templates/forum/reply.jinja:39
 | 
					#: forum/templates/forum/reply.jinja:39
 | 
				
			||||||
#: subscription/templates/subscription/fragments/creation_form.jinja:9
 | 
					#: subscription/templates/subscription/fragments/creation_form.jinja:9
 | 
				
			||||||
@@ -951,11 +950,11 @@ msgstr "Une action est requise"
 | 
				
			|||||||
msgid "You must specify at least an user or an email address"
 | 
					msgid "You must specify at least an user or an email address"
 | 
				
			||||||
msgstr "vous devez spécifier au moins un utilisateur ou une adresse email"
 | 
					msgstr "vous devez spécifier au moins un utilisateur ou une adresse email"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/forms.py:149 counter/forms.py:203
 | 
					#: club/forms.py:149 counter/forms.py:193
 | 
				
			||||||
msgid "Begin date"
 | 
					msgid "Begin date"
 | 
				
			||||||
msgstr "Date de début"
 | 
					msgstr "Date de début"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/forms.py:152 com/views.py:84 com/views.py:202 counter/forms.py:206
 | 
					#: club/forms.py:152 com/views.py:84 com/views.py:202 counter/forms.py:196
 | 
				
			||||||
#: election/views.py:170 subscription/forms.py:21
 | 
					#: election/views.py:170 subscription/forms.py:21
 | 
				
			||||||
msgid "End date"
 | 
					msgid "End date"
 | 
				
			||||||
msgstr "Date de fin"
 | 
					msgstr "Date de fin"
 | 
				
			||||||
@@ -963,15 +962,16 @@ msgstr "Date de fin"
 | 
				
			|||||||
#: club/forms.py:156 club/templates/club/club_sellings.jinja:49
 | 
					#: club/forms.py:156 club/templates/club/club_sellings.jinja:49
 | 
				
			||||||
#: core/templates/core/user_account_detail.jinja:17
 | 
					#: core/templates/core/user_account_detail.jinja:17
 | 
				
			||||||
#: core/templates/core/user_account_detail.jinja:56
 | 
					#: core/templates/core/user_account_detail.jinja:56
 | 
				
			||||||
#: counter/templates/counter/cash_summary_list.jinja:33 counter/views.py:137
 | 
					#: counter/templates/counter/cash_summary_list.jinja:33
 | 
				
			||||||
 | 
					#: counter/views/mixins.py:58
 | 
				
			||||||
msgid "Counter"
 | 
					msgid "Counter"
 | 
				
			||||||
msgstr "Comptoir"
 | 
					msgstr "Comptoir"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/forms.py:163 counter/views.py:683
 | 
					#: club/forms.py:163 counter/views/mixins.py:94
 | 
				
			||||||
msgid "Products"
 | 
					msgid "Products"
 | 
				
			||||||
msgstr "Produits"
 | 
					msgstr "Produits"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/forms.py:168 counter/views.py:688
 | 
					#: club/forms.py:168 counter/views/mixins.py:99
 | 
				
			||||||
msgid "Archived products"
 | 
					msgid "Archived products"
 | 
				
			||||||
msgstr "Produits archivés"
 | 
					msgstr "Produits archivés"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1334,7 +1334,7 @@ msgid "No mailing list existing for this club"
 | 
				
			|||||||
msgstr "Aucune mailing liste n'existe pour ce club"
 | 
					msgstr "Aucune mailing liste n'existe pour ce club"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: club/templates/club/mailing.jinja:72
 | 
					#: club/templates/club/mailing.jinja:72
 | 
				
			||||||
#: subscription/templates/subscription/subscription.jinja:39
 | 
					#: subscription/templates/subscription/subscription.jinja:38
 | 
				
			||||||
msgid "New member"
 | 
					msgid "New member"
 | 
				
			||||||
msgstr "Nouveau membre"
 | 
					msgstr "Nouveau membre"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1426,7 +1426,8 @@ msgstr "Hebdomadaire"
 | 
				
			|||||||
msgid "Call"
 | 
					msgid "Call"
 | 
				
			||||||
msgstr "Appel"
 | 
					msgstr "Appel"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: com/models.py:67 com/models.py:174 com/models.py:248 election/models.py:12
 | 
					#: com/models.py:67 com/models.py:174 com/models.py:248
 | 
				
			||||||
 | 
					#: core/templates/core/macros.jinja:301 election/models.py:12
 | 
				
			||||||
#: election/models.py:114 election/models.py:152 forum/models.py:256
 | 
					#: election/models.py:114 election/models.py:152 forum/models.py:256
 | 
				
			||||||
#: forum/models.py:310 pedagogy/models.py:97
 | 
					#: forum/models.py:310 pedagogy/models.py:97
 | 
				
			||||||
msgid "title"
 | 
					msgid "title"
 | 
				
			||||||
@@ -1835,6 +1836,7 @@ msgid "Articles in no weekmail yet"
 | 
				
			|||||||
msgstr "Articles dans aucun weekmail"
 | 
					msgstr "Articles dans aucun weekmail"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: com/templates/com/weekmail.jinja:20 com/templates/com/weekmail.jinja:49
 | 
					#: com/templates/com/weekmail.jinja:20 com/templates/com/weekmail.jinja:49
 | 
				
			||||||
 | 
					#: core/templates/core/macros.jinja:301
 | 
				
			||||||
msgid "Content"
 | 
					msgid "Content"
 | 
				
			||||||
msgstr "Contenu"
 | 
					msgstr "Contenu"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2505,7 +2507,7 @@ msgstr "Photos"
 | 
				
			|||||||
#: eboutic/templates/eboutic/eboutic_main.jinja:22
 | 
					#: eboutic/templates/eboutic/eboutic_main.jinja:22
 | 
				
			||||||
#: eboutic/templates/eboutic/eboutic_makecommand.jinja:16
 | 
					#: eboutic/templates/eboutic/eboutic_makecommand.jinja:16
 | 
				
			||||||
#: eboutic/templates/eboutic/eboutic_payment_result.jinja:4
 | 
					#: eboutic/templates/eboutic/eboutic_payment_result.jinja:4
 | 
				
			||||||
#: sith/settings.py:420 sith/settings.py:428
 | 
					#: sith/settings.py:422 sith/settings.py:430
 | 
				
			||||||
msgid "Eboutic"
 | 
					msgid "Eboutic"
 | 
				
			||||||
msgstr "Eboutic"
 | 
					msgstr "Eboutic"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2583,7 +2585,7 @@ msgstr "Confirmation"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#: core/templates/core/delete_confirm.jinja:20
 | 
					#: core/templates/core/delete_confirm.jinja:20
 | 
				
			||||||
#: core/templates/core/file_delete_confirm.jinja:46
 | 
					#: core/templates/core/file_delete_confirm.jinja:46
 | 
				
			||||||
#: counter/templates/counter/counter_click.jinja:121
 | 
					#: counter/templates/counter/counter_click.jinja:111
 | 
				
			||||||
#: sas/templates/sas/ask_picture_removal.jinja:20
 | 
					#: sas/templates/sas/ask_picture_removal.jinja:20
 | 
				
			||||||
msgid "Cancel"
 | 
					msgid "Cancel"
 | 
				
			||||||
msgstr "Annuler"
 | 
					msgstr "Annuler"
 | 
				
			||||||
@@ -3042,11 +3044,11 @@ msgid "Eboutic invoices"
 | 
				
			|||||||
msgstr "Facture eboutic"
 | 
					msgstr "Facture eboutic"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: core/templates/core/user_account.jinja:54
 | 
					#: core/templates/core/user_account.jinja:54
 | 
				
			||||||
#: core/templates/core/user_tools.jinja:58 counter/views.py:708
 | 
					#: core/templates/core/user_tools.jinja:58 counter/views/mixins.py:119
 | 
				
			||||||
msgid "Etickets"
 | 
					msgid "Etickets"
 | 
				
			||||||
msgstr "Etickets"
 | 
					msgstr "Etickets"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: core/templates/core/user_account.jinja:69 core/views/user.py:638
 | 
					#: core/templates/core/user_account.jinja:69 core/views/user.py:639
 | 
				
			||||||
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"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3137,7 +3139,7 @@ msgstr "Non cotisant"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#: core/templates/core/user_detail.jinja:162
 | 
					#: core/templates/core/user_detail.jinja:162
 | 
				
			||||||
#: subscription/templates/subscription/subscription.jinja:6
 | 
					#: subscription/templates/subscription/subscription.jinja:6
 | 
				
			||||||
#: subscription/templates/subscription/subscription.jinja:37
 | 
					#: subscription/templates/subscription/subscription.jinja:36
 | 
				
			||||||
msgid "New subscription"
 | 
					msgid "New subscription"
 | 
				
			||||||
msgstr "Nouvelle cotisation"
 | 
					msgstr "Nouvelle cotisation"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3295,15 +3297,7 @@ msgstr "Vous avez déjà choisi ce Trombi: %(trombi)s."
 | 
				
			|||||||
msgid "Go to my Trombi tools"
 | 
					msgid "Go to my Trombi tools"
 | 
				
			||||||
msgstr "Allez à mes outils de Trombi"
 | 
					msgstr "Allez à mes outils de Trombi"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: core/templates/core/user_preferences.jinja:39
 | 
					#: core/templates/core/user_preferences.jinja:49
 | 
				
			||||||
msgid "Student cards"
 | 
					 | 
				
			||||||
msgstr "Cartes étudiante"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: core/templates/core/user_preferences.jinja:54
 | 
					 | 
				
			||||||
msgid "No student card registered."
 | 
					 | 
				
			||||||
msgstr "Aucune carte étudiante enregistrée."
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: core/templates/core/user_preferences.jinja:56
 | 
					 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"You can add a card by asking at a counter or add it yourself here. If you "
 | 
					"You can add a card by asking at a counter or add it yourself here. If you "
 | 
				
			||||||
"want to manually\n"
 | 
					"want to manually\n"
 | 
				
			||||||
@@ -3377,8 +3371,8 @@ msgstr "Cotisations"
 | 
				
			|||||||
msgid "Subscription stats"
 | 
					msgid "Subscription stats"
 | 
				
			||||||
msgstr "Statistiques de cotisation"
 | 
					msgstr "Statistiques de cotisation"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: core/templates/core/user_tools.jinja:48 counter/forms.py:176
 | 
					#: core/templates/core/user_tools.jinja:48 counter/forms.py:166
 | 
				
			||||||
#: counter/views.py:678
 | 
					#: counter/views/mixins.py:89
 | 
				
			||||||
msgid "Counters"
 | 
					msgid "Counters"
 | 
				
			||||||
msgstr "Comptoirs"
 | 
					msgstr "Comptoirs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3395,12 +3389,13 @@ msgid "Product types management"
 | 
				
			|||||||
msgstr "Gestion des types de produit"
 | 
					msgstr "Gestion des types de produit"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: core/templates/core/user_tools.jinja:56
 | 
					#: core/templates/core/user_tools.jinja:56
 | 
				
			||||||
#: counter/templates/counter/cash_summary_list.jinja:23 counter/views.py:698
 | 
					#: counter/templates/counter/cash_summary_list.jinja:23
 | 
				
			||||||
 | 
					#: counter/views/mixins.py:109
 | 
				
			||||||
msgid "Cash register summaries"
 | 
					msgid "Cash register summaries"
 | 
				
			||||||
msgstr "Relevés de caisse"
 | 
					msgstr "Relevés de caisse"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: core/templates/core/user_tools.jinja:57
 | 
					#: core/templates/core/user_tools.jinja:57
 | 
				
			||||||
#: counter/templates/counter/invoices_call.jinja:4 counter/views.py:703
 | 
					#: counter/templates/counter/invoices_call.jinja:4 counter/views/mixins.py:114
 | 
				
			||||||
msgid "Invoices call"
 | 
					msgid "Invoices call"
 | 
				
			||||||
msgstr "Appels à facture"
 | 
					msgstr "Appels à facture"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3548,7 +3543,7 @@ msgstr "Parrain / Marraine"
 | 
				
			|||||||
msgid "Godchild"
 | 
					msgid "Godchild"
 | 
				
			||||||
msgstr "Fillot / Fillote"
 | 
					msgstr "Fillot / Fillote"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: core/views/forms.py:310 counter/forms.py:82 trombi/views.py:151
 | 
					#: core/views/forms.py:310 counter/forms.py:80 trombi/views.py:151
 | 
				
			||||||
msgid "Select user"
 | 
					msgid "Select user"
 | 
				
			||||||
msgstr "Choisir un utilisateur"
 | 
					msgstr "Choisir un utilisateur"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3601,15 +3596,15 @@ msgstr "Galaxie"
 | 
				
			|||||||
msgid "counter"
 | 
					msgid "counter"
 | 
				
			||||||
msgstr "comptoir"
 | 
					msgstr "comptoir"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/forms.py:63
 | 
					#: counter/forms.py:61
 | 
				
			||||||
msgid "This UID is invalid"
 | 
					msgid "This UID is invalid"
 | 
				
			||||||
msgstr "Cet UID est invalide"
 | 
					msgstr "Cet UID est invalide"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/forms.py:111
 | 
					#: counter/forms.py:109
 | 
				
			||||||
msgid "User not found"
 | 
					msgid "User not found"
 | 
				
			||||||
msgstr "Utilisateur non trouvé"
 | 
					msgstr "Utilisateur non trouvé"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/management/commands/dump_accounts.py:141
 | 
					#: counter/management/commands/dump_accounts.py:148
 | 
				
			||||||
msgid "Your AE account has been emptied"
 | 
					msgid "Your AE account has been emptied"
 | 
				
			||||||
msgstr "Votre compte AE a été vidé"
 | 
					msgstr "Votre compte AE a été vidé"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3637,7 +3632,7 @@ msgstr "client"
 | 
				
			|||||||
msgid "customers"
 | 
					msgid "customers"
 | 
				
			||||||
msgstr "clients"
 | 
					msgstr "clients"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/models.py:110 counter/views.py:261
 | 
					#: counter/models.py:110 counter/views/click.py:66
 | 
				
			||||||
msgid "Not enough money"
 | 
					msgid "Not enough money"
 | 
				
			||||||
msgstr "Solde insuffisant"
 | 
					msgstr "Solde insuffisant"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3777,8 +3772,8 @@ msgstr "quantité"
 | 
				
			|||||||
msgid "Sith account"
 | 
					msgid "Sith account"
 | 
				
			||||||
msgstr "Compte utilisateur"
 | 
					msgstr "Compte utilisateur"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/models.py:797 sith/settings.py:413 sith/settings.py:418
 | 
					#: counter/models.py:797 sith/settings.py:415 sith/settings.py:420
 | 
				
			||||||
#: sith/settings.py:438
 | 
					#: sith/settings.py:440
 | 
				
			||||||
msgid "Credit card"
 | 
					msgid "Credit card"
 | 
				
			||||||
msgstr "Carte bancaire"
 | 
					msgstr "Carte bancaire"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3910,7 +3905,8 @@ 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:36 counter/views.py:956
 | 
					#: counter/templates/counter/cash_summary_list.jinja:36
 | 
				
			||||||
 | 
					#: counter/views/cash.py:88
 | 
				
			||||||
msgid "Emptied"
 | 
					msgid "Emptied"
 | 
				
			||||||
msgstr "Coffre vidé"
 | 
					msgstr "Coffre vidé"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3922,17 +3918,14 @@ msgstr "oui"
 | 
				
			|||||||
msgid "There is no cash register summary in this website."
 | 
					msgid "There is no cash register summary in this website."
 | 
				
			||||||
msgstr "Il n'y a pas de relevé de caisse dans ce site web."
 | 
					msgstr "Il n'y a pas de relevé de caisse dans ce site web."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/templates/counter/counter_click.jinja:35
 | 
					#: counter/templates/counter/counter_click.jinja:46
 | 
				
			||||||
msgid "Add a student card"
 | 
					#: launderette/templates/launderette/launderette_admin.jinja:8
 | 
				
			||||||
msgstr "Ajouter une carte étudiante"
 | 
					msgid "Selling"
 | 
				
			||||||
 | 
					msgstr "Vente"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/templates/counter/counter_click.jinja:38
 | 
					#: counter/templates/counter/counter_click.jinja:57
 | 
				
			||||||
msgid "This is not a valid student card UID"
 | 
					#: counter/templates/counter/counter_click.jinja:122
 | 
				
			||||||
msgstr "Ce n'est pas un UID de carte étudiante valide"
 | 
					#: counter/templates/counter/fragments/create_student_card.jinja:10
 | 
				
			||||||
 | 
					 | 
				
			||||||
#: counter/templates/counter/counter_click.jinja:40
 | 
					 | 
				
			||||||
#: counter/templates/counter/counter_click.jinja:67
 | 
					 | 
				
			||||||
#: counter/templates/counter/counter_click.jinja:132
 | 
					 | 
				
			||||||
#: counter/templates/counter/invoices_call.jinja:16
 | 
					#: counter/templates/counter/invoices_call.jinja:16
 | 
				
			||||||
#: launderette/templates/launderette/launderette_admin.jinja:35
 | 
					#: launderette/templates/launderette/launderette_admin.jinja:35
 | 
				
			||||||
#: launderette/templates/launderette/launderette_click.jinja:13
 | 
					#: launderette/templates/launderette/launderette_click.jinja:13
 | 
				
			||||||
@@ -3941,29 +3934,16 @@ msgstr "Ce n'est pas un UID de carte étudiante valide"
 | 
				
			|||||||
msgid "Go"
 | 
					msgid "Go"
 | 
				
			||||||
msgstr "Valider"
 | 
					msgstr "Valider"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/templates/counter/counter_click.jinja:42
 | 
					#: counter/templates/counter/counter_click.jinja:64
 | 
				
			||||||
msgid "Registered cards"
 | 
					 | 
				
			||||||
msgstr "Cartes enregistrées"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: counter/templates/counter/counter_click.jinja:51
 | 
					 | 
				
			||||||
msgid "No card registered"
 | 
					 | 
				
			||||||
msgstr "Aucune carte enregistrée"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: counter/templates/counter/counter_click.jinja:56
 | 
					 | 
				
			||||||
#: launderette/templates/launderette/launderette_admin.jinja:8
 | 
					 | 
				
			||||||
msgid "Selling"
 | 
					 | 
				
			||||||
msgstr "Vente"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: counter/templates/counter/counter_click.jinja:74
 | 
					 | 
				
			||||||
#: eboutic/templates/eboutic/eboutic_makecommand.jinja:19
 | 
					#: eboutic/templates/eboutic/eboutic_makecommand.jinja:19
 | 
				
			||||||
msgid "Basket: "
 | 
					msgid "Basket: "
 | 
				
			||||||
msgstr "Panier : "
 | 
					msgstr "Panier : "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/templates/counter/counter_click.jinja:115
 | 
					#: counter/templates/counter/counter_click.jinja:105
 | 
				
			||||||
msgid "Finish"
 | 
					msgid "Finish"
 | 
				
			||||||
msgstr "Terminer"
 | 
					msgstr "Terminer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/templates/counter/counter_click.jinja:125
 | 
					#: counter/templates/counter/counter_click.jinja:115
 | 
				
			||||||
#: counter/templates/counter/refilling_list.jinja:9
 | 
					#: counter/templates/counter/refilling_list.jinja:9
 | 
				
			||||||
msgid "Refilling"
 | 
					msgid "Refilling"
 | 
				
			||||||
msgstr "Rechargement"
 | 
					msgstr "Rechargement"
 | 
				
			||||||
@@ -4047,6 +4027,18 @@ msgstr "Nouveau eticket"
 | 
				
			|||||||
msgid "There is no eticket in this website."
 | 
					msgid "There is no eticket in this website."
 | 
				
			||||||
msgstr "Il n'y a pas de eticket sur ce site web."
 | 
					msgstr "Il n'y a pas de eticket sur ce site web."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: counter/templates/counter/fragments/create_student_card.jinja:2
 | 
				
			||||||
 | 
					msgid "Add a student card"
 | 
				
			||||||
 | 
					msgstr "Ajouter une carte étudiante"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: counter/templates/counter/fragments/create_student_card.jinja:13
 | 
				
			||||||
 | 
					msgid "Registered cards"
 | 
				
			||||||
 | 
					msgstr "Cartes enregistrées"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: counter/templates/counter/fragments/create_student_card.jinja:27
 | 
				
			||||||
 | 
					msgid "No student card registered."
 | 
				
			||||||
 | 
					msgstr "Aucune carte étudiante enregistrée."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/templates/counter/invoices_call.jinja:8
 | 
					#: counter/templates/counter/invoices_call.jinja:8
 | 
				
			||||||
#, python-format
 | 
					#, python-format
 | 
				
			||||||
msgid "Invoices call for %(date)s"
 | 
					msgid "Invoices call for %(date)s"
 | 
				
			||||||
@@ -4219,104 +4211,104 @@ msgstr "Temps"
 | 
				
			|||||||
msgid "Top 100 barman %(counter_name)s (all semesters)"
 | 
					msgid "Top 100 barman %(counter_name)s (all semesters)"
 | 
				
			||||||
msgstr "Top 100 barman %(counter_name)s (tous les semestres)"
 | 
					msgstr "Top 100 barman %(counter_name)s (tous les semestres)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/views.py:147
 | 
					#: counter/views/cash.py:45
 | 
				
			||||||
msgid "Cash summary"
 | 
					 | 
				
			||||||
msgstr "Relevé de caisse"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: counter/views.py:156
 | 
					 | 
				
			||||||
msgid "Last operations"
 | 
					 | 
				
			||||||
msgstr "Dernières opérations"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: counter/views.py:203
 | 
					 | 
				
			||||||
msgid "Bad credentials"
 | 
					 | 
				
			||||||
msgstr "Mauvais identifiants"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: counter/views.py:205
 | 
					 | 
				
			||||||
msgid "User is not barman"
 | 
					 | 
				
			||||||
msgstr "L'utilisateur n'est pas barman."
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: counter/views.py:210
 | 
					 | 
				
			||||||
msgid "Bad location, someone is already logged in somewhere else"
 | 
					 | 
				
			||||||
msgstr "Mauvais comptoir, quelqu'un est déjà connecté ailleurs"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: counter/views.py:252
 | 
					 | 
				
			||||||
msgid "Too young for that product"
 | 
					 | 
				
			||||||
msgstr "Trop jeune pour ce produit"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: counter/views.py:255
 | 
					 | 
				
			||||||
msgid "Not allowed for that product"
 | 
					 | 
				
			||||||
msgstr "Non autorisé pour ce produit"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: counter/views.py:258
 | 
					 | 
				
			||||||
msgid "No date of birth provided"
 | 
					 | 
				
			||||||
msgstr "Pas de date de naissance renseignée"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: counter/views.py:546
 | 
					 | 
				
			||||||
msgid "You have not enough money to buy all the basket"
 | 
					 | 
				
			||||||
msgstr "Vous n'avez pas assez d'argent pour acheter le panier"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: counter/views.py:673
 | 
					 | 
				
			||||||
msgid "Counter administration"
 | 
					 | 
				
			||||||
msgstr "Administration des comptoirs"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: counter/views.py:693
 | 
					 | 
				
			||||||
msgid "Product types"
 | 
					 | 
				
			||||||
msgstr "Types de produit"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: counter/views.py:913
 | 
					 | 
				
			||||||
msgid "10 cents"
 | 
					msgid "10 cents"
 | 
				
			||||||
msgstr "10 centimes"
 | 
					msgstr "10 centimes"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/views.py:914
 | 
					#: counter/views/cash.py:46
 | 
				
			||||||
msgid "20 cents"
 | 
					msgid "20 cents"
 | 
				
			||||||
msgstr "20 centimes"
 | 
					msgstr "20 centimes"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/views.py:915
 | 
					#: counter/views/cash.py:47
 | 
				
			||||||
msgid "50 cents"
 | 
					msgid "50 cents"
 | 
				
			||||||
msgstr "50 centimes"
 | 
					msgstr "50 centimes"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/views.py:916
 | 
					#: counter/views/cash.py:48
 | 
				
			||||||
msgid "1 euro"
 | 
					msgid "1 euro"
 | 
				
			||||||
msgstr "1 €"
 | 
					msgstr "1 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/views.py:917
 | 
					#: counter/views/cash.py:49
 | 
				
			||||||
msgid "2 euros"
 | 
					msgid "2 euros"
 | 
				
			||||||
msgstr "2 €"
 | 
					msgstr "2 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/views.py:918
 | 
					#: counter/views/cash.py:50
 | 
				
			||||||
msgid "5 euros"
 | 
					msgid "5 euros"
 | 
				
			||||||
msgstr "5 €"
 | 
					msgstr "5 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/views.py:919
 | 
					#: counter/views/cash.py:51
 | 
				
			||||||
msgid "10 euros"
 | 
					msgid "10 euros"
 | 
				
			||||||
msgstr "10 €"
 | 
					msgstr "10 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/views.py:920
 | 
					#: counter/views/cash.py:52
 | 
				
			||||||
msgid "20 euros"
 | 
					msgid "20 euros"
 | 
				
			||||||
msgstr "20 €"
 | 
					msgstr "20 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/views.py:921
 | 
					#: counter/views/cash.py:53
 | 
				
			||||||
msgid "50 euros"
 | 
					msgid "50 euros"
 | 
				
			||||||
msgstr "50 €"
 | 
					msgstr "50 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/views.py:923
 | 
					#: counter/views/cash.py:55
 | 
				
			||||||
msgid "100 euros"
 | 
					msgid "100 euros"
 | 
				
			||||||
msgstr "100 €"
 | 
					msgstr "100 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/views.py:926 counter/views.py:932 counter/views.py:938
 | 
					#: counter/views/cash.py:58 counter/views/cash.py:64 counter/views/cash.py:70
 | 
				
			||||||
#: counter/views.py:944 counter/views.py:950
 | 
					#: counter/views/cash.py:76 counter/views/cash.py:82
 | 
				
			||||||
msgid "Check amount"
 | 
					msgid "Check amount"
 | 
				
			||||||
msgstr "Montant du chèque"
 | 
					msgstr "Montant du chèque"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/views.py:929 counter/views.py:935 counter/views.py:941
 | 
					#: counter/views/cash.py:61 counter/views/cash.py:67 counter/views/cash.py:73
 | 
				
			||||||
#: counter/views.py:947 counter/views.py:953
 | 
					#: counter/views/cash.py:79 counter/views/cash.py:85
 | 
				
			||||||
msgid "Check quantity"
 | 
					msgid "Check quantity"
 | 
				
			||||||
msgstr "Nombre de chèque"
 | 
					msgstr "Nombre de chèque"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: counter/views.py:1473
 | 
					#: counter/views/click.py:57
 | 
				
			||||||
 | 
					msgid "Too young for that product"
 | 
				
			||||||
 | 
					msgstr "Trop jeune pour ce produit"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: counter/views/click.py:60
 | 
				
			||||||
 | 
					msgid "Not allowed for that product"
 | 
				
			||||||
 | 
					msgstr "Non autorisé pour ce produit"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: counter/views/click.py:63
 | 
				
			||||||
 | 
					msgid "No date of birth provided"
 | 
				
			||||||
 | 
					msgstr "Pas de date de naissance renseignée"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: counter/views/click.py:331
 | 
				
			||||||
 | 
					msgid "You have not enough money to buy all the basket"
 | 
				
			||||||
 | 
					msgstr "Vous n'avez pas assez d'argent pour acheter le panier"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: counter/views/eticket.py:120
 | 
				
			||||||
msgid "people(s)"
 | 
					msgid "people(s)"
 | 
				
			||||||
msgstr "personne(s)"
 | 
					msgstr "personne(s)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: counter/views/home.py:74
 | 
				
			||||||
 | 
					msgid "Bad credentials"
 | 
				
			||||||
 | 
					msgstr "Mauvais identifiants"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: counter/views/home.py:76
 | 
				
			||||||
 | 
					msgid "User is not barman"
 | 
				
			||||||
 | 
					msgstr "L'utilisateur n'est pas barman."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: counter/views/home.py:81
 | 
				
			||||||
 | 
					msgid "Bad location, someone is already logged in somewhere else"
 | 
				
			||||||
 | 
					msgstr "Mauvais comptoir, quelqu'un est déjà connecté ailleurs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: counter/views/mixins.py:68
 | 
				
			||||||
 | 
					msgid "Cash summary"
 | 
				
			||||||
 | 
					msgstr "Relevé de caisse"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: counter/views/mixins.py:77
 | 
				
			||||||
 | 
					msgid "Last operations"
 | 
				
			||||||
 | 
					msgstr "Dernières opérations"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: counter/views/mixins.py:84
 | 
				
			||||||
 | 
					msgid "Counter administration"
 | 
				
			||||||
 | 
					msgstr "Administration des comptoirs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: counter/views/mixins.py:104
 | 
				
			||||||
 | 
					msgid "Product types"
 | 
				
			||||||
 | 
					msgstr "Types de produit"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: eboutic/forms.py:88
 | 
					#: eboutic/forms.py:88
 | 
				
			||||||
msgid "The request was badly formatted."
 | 
					msgid "The request was badly formatted."
 | 
				
			||||||
msgstr "La requête a été mal formatée."
 | 
					msgstr "La requête a été mal formatée."
 | 
				
			||||||
@@ -4894,12 +4886,12 @@ msgid "Washing and drying"
 | 
				
			|||||||
msgstr "Lavage et séchage"
 | 
					msgstr "Lavage et séchage"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: launderette/templates/launderette/launderette_book.jinja:27
 | 
					#: launderette/templates/launderette/launderette_book.jinja:27
 | 
				
			||||||
#: sith/settings.py:656
 | 
					#: sith/settings.py:658
 | 
				
			||||||
msgid "Washing"
 | 
					msgid "Washing"
 | 
				
			||||||
msgstr "Lavage"
 | 
					msgstr "Lavage"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: launderette/templates/launderette/launderette_book.jinja:31
 | 
					#: launderette/templates/launderette/launderette_book.jinja:31
 | 
				
			||||||
#: sith/settings.py:656
 | 
					#: sith/settings.py:658
 | 
				
			||||||
msgid "Drying"
 | 
					msgid "Drying"
 | 
				
			||||||
msgstr "Séchage"
 | 
					msgstr "Séchage"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -5414,380 +5406,380 @@ msgstr "Personne(s)"
 | 
				
			|||||||
msgid "Identify users on pictures"
 | 
					msgid "Identify users on pictures"
 | 
				
			||||||
msgstr "Identifiez les utilisateurs sur les photos"
 | 
					msgstr "Identifiez les utilisateurs sur les photos"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:254 sith/settings.py:475
 | 
					#: sith/settings.py:253 sith/settings.py:477
 | 
				
			||||||
msgid "English"
 | 
					msgid "English"
 | 
				
			||||||
msgstr "Anglais"
 | 
					msgstr "Anglais"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:254 sith/settings.py:474
 | 
					#: sith/settings.py:253 sith/settings.py:476
 | 
				
			||||||
msgid "French"
 | 
					msgid "French"
 | 
				
			||||||
msgstr "Français"
 | 
					msgstr "Français"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:394
 | 
					#: sith/settings.py:396
 | 
				
			||||||
msgid "TC"
 | 
					msgid "TC"
 | 
				
			||||||
msgstr "TC"
 | 
					msgstr "TC"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:395
 | 
					#: sith/settings.py:397
 | 
				
			||||||
msgid "IMSI"
 | 
					msgid "IMSI"
 | 
				
			||||||
msgstr "IMSI"
 | 
					msgstr "IMSI"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:396
 | 
					#: sith/settings.py:398
 | 
				
			||||||
msgid "IMAP"
 | 
					msgid "IMAP"
 | 
				
			||||||
msgstr "IMAP"
 | 
					msgstr "IMAP"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:397
 | 
					#: sith/settings.py:399
 | 
				
			||||||
msgid "INFO"
 | 
					msgid "INFO"
 | 
				
			||||||
msgstr "INFO"
 | 
					msgstr "INFO"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:398
 | 
					#: sith/settings.py:400
 | 
				
			||||||
msgid "GI"
 | 
					msgid "GI"
 | 
				
			||||||
msgstr "GI"
 | 
					msgstr "GI"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:399 sith/settings.py:485
 | 
					#: sith/settings.py:401 sith/settings.py:487
 | 
				
			||||||
msgid "E"
 | 
					msgid "E"
 | 
				
			||||||
msgstr "E"
 | 
					msgstr "E"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:400
 | 
					#: sith/settings.py:402
 | 
				
			||||||
msgid "EE"
 | 
					msgid "EE"
 | 
				
			||||||
msgstr "EE"
 | 
					msgstr "EE"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:401
 | 
					#: sith/settings.py:403
 | 
				
			||||||
msgid "GESC"
 | 
					msgid "GESC"
 | 
				
			||||||
msgstr "GESC"
 | 
					msgstr "GESC"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:402
 | 
					#: sith/settings.py:404
 | 
				
			||||||
msgid "GMC"
 | 
					msgid "GMC"
 | 
				
			||||||
msgstr "GMC"
 | 
					msgstr "GMC"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:403
 | 
					#: sith/settings.py:405
 | 
				
			||||||
msgid "MC"
 | 
					msgid "MC"
 | 
				
			||||||
msgstr "MC"
 | 
					msgstr "MC"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:404
 | 
					#: sith/settings.py:406
 | 
				
			||||||
msgid "EDIM"
 | 
					msgid "EDIM"
 | 
				
			||||||
msgstr "EDIM"
 | 
					msgstr "EDIM"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:405
 | 
					#: sith/settings.py:407
 | 
				
			||||||
msgid "Humanities"
 | 
					msgid "Humanities"
 | 
				
			||||||
msgstr "Humanités"
 | 
					msgstr "Humanités"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:406
 | 
					#: sith/settings.py:408
 | 
				
			||||||
msgid "N/A"
 | 
					msgid "N/A"
 | 
				
			||||||
msgstr "N/A"
 | 
					msgstr "N/A"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:410 sith/settings.py:417 sith/settings.py:436
 | 
					#: sith/settings.py:412 sith/settings.py:419 sith/settings.py:438
 | 
				
			||||||
msgid "Check"
 | 
					msgid "Check"
 | 
				
			||||||
msgstr "Chèque"
 | 
					msgstr "Chèque"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:411 sith/settings.py:419 sith/settings.py:437
 | 
					#: sith/settings.py:413 sith/settings.py:421 sith/settings.py:439
 | 
				
			||||||
msgid "Cash"
 | 
					msgid "Cash"
 | 
				
			||||||
msgstr "Espèces"
 | 
					msgstr "Espèces"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:412
 | 
					#: sith/settings.py:414
 | 
				
			||||||
msgid "Transfert"
 | 
					msgid "Transfert"
 | 
				
			||||||
msgstr "Virement"
 | 
					msgstr "Virement"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:425
 | 
					#: sith/settings.py:427
 | 
				
			||||||
msgid "Belfort"
 | 
					msgid "Belfort"
 | 
				
			||||||
msgstr "Belfort"
 | 
					msgstr "Belfort"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:426
 | 
					#: sith/settings.py:428
 | 
				
			||||||
msgid "Sevenans"
 | 
					msgid "Sevenans"
 | 
				
			||||||
msgstr "Sevenans"
 | 
					msgstr "Sevenans"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:427
 | 
					#: sith/settings.py:429
 | 
				
			||||||
msgid "Montbéliard"
 | 
					msgid "Montbéliard"
 | 
				
			||||||
msgstr "Montbéliard"
 | 
					msgstr "Montbéliard"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:455
 | 
					#: sith/settings.py:457
 | 
				
			||||||
msgid "Free"
 | 
					msgid "Free"
 | 
				
			||||||
msgstr "Libre"
 | 
					msgstr "Libre"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:456
 | 
					#: sith/settings.py:458
 | 
				
			||||||
msgid "CS"
 | 
					msgid "CS"
 | 
				
			||||||
msgstr "CS"
 | 
					msgstr "CS"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:457
 | 
					#: sith/settings.py:459
 | 
				
			||||||
msgid "TM"
 | 
					msgid "TM"
 | 
				
			||||||
msgstr "TM"
 | 
					msgstr "TM"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:458
 | 
					#: sith/settings.py:460
 | 
				
			||||||
msgid "OM"
 | 
					msgid "OM"
 | 
				
			||||||
msgstr "OM"
 | 
					msgstr "OM"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:459
 | 
					#: sith/settings.py:461
 | 
				
			||||||
msgid "QC"
 | 
					msgid "QC"
 | 
				
			||||||
msgstr "QC"
 | 
					msgstr "QC"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:460
 | 
					#: sith/settings.py:462
 | 
				
			||||||
msgid "EC"
 | 
					msgid "EC"
 | 
				
			||||||
msgstr "EC"
 | 
					msgstr "EC"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:461
 | 
					#: sith/settings.py:463
 | 
				
			||||||
msgid "RN"
 | 
					msgid "RN"
 | 
				
			||||||
msgstr "RN"
 | 
					msgstr "RN"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:462
 | 
					#: sith/settings.py:464
 | 
				
			||||||
msgid "ST"
 | 
					msgid "ST"
 | 
				
			||||||
msgstr "ST"
 | 
					msgstr "ST"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:463
 | 
					#: sith/settings.py:465
 | 
				
			||||||
msgid "EXT"
 | 
					msgid "EXT"
 | 
				
			||||||
msgstr "EXT"
 | 
					msgstr "EXT"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:468
 | 
					#: sith/settings.py:470
 | 
				
			||||||
msgid "Autumn"
 | 
					msgid "Autumn"
 | 
				
			||||||
msgstr "Automne"
 | 
					msgstr "Automne"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:469
 | 
					#: sith/settings.py:471
 | 
				
			||||||
msgid "Spring"
 | 
					msgid "Spring"
 | 
				
			||||||
msgstr "Printemps"
 | 
					msgstr "Printemps"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:470
 | 
					#: sith/settings.py:472
 | 
				
			||||||
msgid "Autumn and spring"
 | 
					msgid "Autumn and spring"
 | 
				
			||||||
msgstr "Automne et printemps"
 | 
					msgstr "Automne et printemps"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:476
 | 
					#: sith/settings.py:478
 | 
				
			||||||
msgid "German"
 | 
					msgid "German"
 | 
				
			||||||
msgstr "Allemand"
 | 
					msgstr "Allemand"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:477
 | 
					#: sith/settings.py:479
 | 
				
			||||||
msgid "Spanish"
 | 
					msgid "Spanish"
 | 
				
			||||||
msgstr "Espagnol"
 | 
					msgstr "Espagnol"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:481
 | 
					#: sith/settings.py:483
 | 
				
			||||||
msgid "A"
 | 
					msgid "A"
 | 
				
			||||||
msgstr "A"
 | 
					msgstr "A"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:482
 | 
					#: sith/settings.py:484
 | 
				
			||||||
msgid "B"
 | 
					msgid "B"
 | 
				
			||||||
msgstr "B"
 | 
					msgstr "B"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:483
 | 
					#: sith/settings.py:485
 | 
				
			||||||
msgid "C"
 | 
					msgid "C"
 | 
				
			||||||
msgstr "C"
 | 
					msgstr "C"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:484
 | 
					#: sith/settings.py:486
 | 
				
			||||||
msgid "D"
 | 
					msgid "D"
 | 
				
			||||||
msgstr "D"
 | 
					msgstr "D"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:486
 | 
					#: sith/settings.py:488
 | 
				
			||||||
msgid "FX"
 | 
					msgid "FX"
 | 
				
			||||||
msgstr "FX"
 | 
					msgstr "FX"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:487
 | 
					#: sith/settings.py:489
 | 
				
			||||||
msgid "F"
 | 
					msgid "F"
 | 
				
			||||||
msgstr "F"
 | 
					msgstr "F"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:488
 | 
					#: sith/settings.py:490
 | 
				
			||||||
msgid "Abs"
 | 
					msgid "Abs"
 | 
				
			||||||
msgstr "Abs"
 | 
					msgstr "Abs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:492
 | 
					#: sith/settings.py:494
 | 
				
			||||||
msgid "Selling deletion"
 | 
					msgid "Selling deletion"
 | 
				
			||||||
msgstr "Suppression de vente"
 | 
					msgstr "Suppression de vente"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:493
 | 
					#: sith/settings.py:495
 | 
				
			||||||
msgid "Refilling deletion"
 | 
					msgid "Refilling deletion"
 | 
				
			||||||
msgstr "Suppression de rechargement"
 | 
					msgstr "Suppression de rechargement"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:537
 | 
					#: sith/settings.py:539
 | 
				
			||||||
msgid "One semester"
 | 
					msgid "One semester"
 | 
				
			||||||
msgstr "Un semestre, 20 €"
 | 
					msgstr "Un semestre, 20 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:538
 | 
					#: sith/settings.py:540
 | 
				
			||||||
msgid "Two semesters"
 | 
					msgid "Two semesters"
 | 
				
			||||||
msgstr "Deux semestres, 35 €"
 | 
					msgstr "Deux semestres, 35 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:540
 | 
					#: sith/settings.py:542
 | 
				
			||||||
msgid "Common core cursus"
 | 
					msgid "Common core cursus"
 | 
				
			||||||
msgstr "Cursus tronc commun, 60 €"
 | 
					msgstr "Cursus tronc commun, 60 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:544
 | 
					#: sith/settings.py:546
 | 
				
			||||||
msgid "Branch cursus"
 | 
					msgid "Branch cursus"
 | 
				
			||||||
msgstr "Cursus branche, 60 €"
 | 
					msgstr "Cursus branche, 60 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:545
 | 
					#: sith/settings.py:547
 | 
				
			||||||
msgid "Alternating cursus"
 | 
					msgid "Alternating cursus"
 | 
				
			||||||
msgstr "Cursus alternant, 30 €"
 | 
					msgstr "Cursus alternant, 30 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:546
 | 
					#: sith/settings.py:548
 | 
				
			||||||
msgid "Honorary member"
 | 
					msgid "Honorary member"
 | 
				
			||||||
msgstr "Membre honoraire, 0 €"
 | 
					msgstr "Membre honoraire, 0 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:547
 | 
					#: sith/settings.py:549
 | 
				
			||||||
msgid "Assidu member"
 | 
					msgid "Assidu member"
 | 
				
			||||||
msgstr "Membre d'Assidu, 0 €"
 | 
					msgstr "Membre d'Assidu, 0 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:548
 | 
					#: sith/settings.py:550
 | 
				
			||||||
msgid "Amicale/DOCEO member"
 | 
					msgid "Amicale/DOCEO member"
 | 
				
			||||||
msgstr "Membre de l'Amicale/DOCEO, 0 €"
 | 
					msgstr "Membre de l'Amicale/DOCEO, 0 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:549
 | 
					#: sith/settings.py:551
 | 
				
			||||||
msgid "UT network member"
 | 
					msgid "UT network member"
 | 
				
			||||||
msgstr "Cotisant du réseau UT, 0 €"
 | 
					msgstr "Cotisant du réseau UT, 0 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:550
 | 
					#: sith/settings.py:552
 | 
				
			||||||
msgid "CROUS member"
 | 
					msgid "CROUS member"
 | 
				
			||||||
msgstr "Membres du CROUS, 0 €"
 | 
					msgstr "Membres du CROUS, 0 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:551
 | 
					#: sith/settings.py:553
 | 
				
			||||||
msgid "Sbarro/ESTA member"
 | 
					msgid "Sbarro/ESTA member"
 | 
				
			||||||
msgstr "Membre de Sbarro ou de l'ESTA, 20 €"
 | 
					msgstr "Membre de Sbarro ou de l'ESTA, 20 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:553
 | 
					#: sith/settings.py:555
 | 
				
			||||||
msgid "One semester Welcome Week"
 | 
					msgid "One semester Welcome Week"
 | 
				
			||||||
msgstr "Un semestre Welcome Week"
 | 
					msgstr "Un semestre Welcome Week"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:557
 | 
					#: sith/settings.py:559
 | 
				
			||||||
msgid "One month for free"
 | 
					msgid "One month for free"
 | 
				
			||||||
msgstr "Un mois gratuit"
 | 
					msgstr "Un mois gratuit"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:558
 | 
					#: sith/settings.py:560
 | 
				
			||||||
msgid "Two months for free"
 | 
					msgid "Two months for free"
 | 
				
			||||||
msgstr "Deux mois gratuits"
 | 
					msgstr "Deux mois gratuits"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:559
 | 
					#: sith/settings.py:561
 | 
				
			||||||
msgid "Eurok's volunteer"
 | 
					msgid "Eurok's volunteer"
 | 
				
			||||||
msgstr "Bénévole Eurockéennes"
 | 
					msgstr "Bénévole Eurockéennes"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:561
 | 
					#: sith/settings.py:563
 | 
				
			||||||
msgid "Six weeks for free"
 | 
					msgid "Six weeks for free"
 | 
				
			||||||
msgstr "6 semaines gratuites"
 | 
					msgstr "6 semaines gratuites"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:565
 | 
					#: sith/settings.py:567
 | 
				
			||||||
msgid "One day"
 | 
					msgid "One day"
 | 
				
			||||||
msgstr "Un jour"
 | 
					msgstr "Un jour"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:566
 | 
					#: sith/settings.py:568
 | 
				
			||||||
msgid "GA staff member"
 | 
					msgid "GA staff member"
 | 
				
			||||||
msgstr "Membre staff GA (2 semaines), 1 €"
 | 
					msgstr "Membre staff GA (2 semaines), 1 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:569
 | 
					#: sith/settings.py:571
 | 
				
			||||||
msgid "One semester (-20%)"
 | 
					msgid "One semester (-20%)"
 | 
				
			||||||
msgstr "Un semestre (-20%), 12 €"
 | 
					msgstr "Un semestre (-20%), 12 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:574
 | 
					#: sith/settings.py:576
 | 
				
			||||||
msgid "Two semesters (-20%)"
 | 
					msgid "Two semesters (-20%)"
 | 
				
			||||||
msgstr "Deux semestres (-20%), 22 €"
 | 
					msgstr "Deux semestres (-20%), 22 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:579
 | 
					#: sith/settings.py:581
 | 
				
			||||||
msgid "Common core cursus (-20%)"
 | 
					msgid "Common core cursus (-20%)"
 | 
				
			||||||
msgstr "Cursus tronc commun (-20%), 36 €"
 | 
					msgstr "Cursus tronc commun (-20%), 36 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:584
 | 
					#: sith/settings.py:586
 | 
				
			||||||
msgid "Branch cursus (-20%)"
 | 
					msgid "Branch cursus (-20%)"
 | 
				
			||||||
msgstr "Cursus branche (-20%), 36 €"
 | 
					msgstr "Cursus branche (-20%), 36 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:589
 | 
					#: sith/settings.py:591
 | 
				
			||||||
msgid "Alternating cursus (-20%)"
 | 
					msgid "Alternating cursus (-20%)"
 | 
				
			||||||
msgstr "Cursus alternant (-20%), 24 €"
 | 
					msgstr "Cursus alternant (-20%), 24 €"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:595
 | 
					#: sith/settings.py:597
 | 
				
			||||||
msgid "One year for free(CA offer)"
 | 
					msgid "One year for free(CA offer)"
 | 
				
			||||||
msgstr "Une année offerte (Offre CA)"
 | 
					msgstr "Une année offerte (Offre CA)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:615
 | 
					#: sith/settings.py:617
 | 
				
			||||||
msgid "President"
 | 
					msgid "President"
 | 
				
			||||||
msgstr "Président⸱e"
 | 
					msgstr "Président⸱e"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:616
 | 
					#: sith/settings.py:618
 | 
				
			||||||
msgid "Vice-President"
 | 
					msgid "Vice-President"
 | 
				
			||||||
msgstr "Vice-Président⸱e"
 | 
					msgstr "Vice-Président⸱e"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:617
 | 
					#: sith/settings.py:619
 | 
				
			||||||
msgid "Treasurer"
 | 
					msgid "Treasurer"
 | 
				
			||||||
msgstr "Trésorier⸱e"
 | 
					msgstr "Trésorier⸱e"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:618
 | 
					#: sith/settings.py:620
 | 
				
			||||||
msgid "Communication supervisor"
 | 
					msgid "Communication supervisor"
 | 
				
			||||||
msgstr "Responsable communication"
 | 
					msgstr "Responsable communication"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:619
 | 
					#: sith/settings.py:621
 | 
				
			||||||
msgid "Secretary"
 | 
					msgid "Secretary"
 | 
				
			||||||
msgstr "Secrétaire"
 | 
					msgstr "Secrétaire"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:620
 | 
					#: sith/settings.py:622
 | 
				
			||||||
msgid "IT supervisor"
 | 
					msgid "IT supervisor"
 | 
				
			||||||
msgstr "Responsable info"
 | 
					msgstr "Responsable info"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:621
 | 
					#: sith/settings.py:623
 | 
				
			||||||
msgid "Board member"
 | 
					msgid "Board member"
 | 
				
			||||||
msgstr "Membre du bureau"
 | 
					msgstr "Membre du bureau"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:622
 | 
					#: sith/settings.py:624
 | 
				
			||||||
msgid "Active member"
 | 
					msgid "Active member"
 | 
				
			||||||
msgstr "Membre actif⸱ve"
 | 
					msgstr "Membre actif⸱ve"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:623
 | 
					#: sith/settings.py:625
 | 
				
			||||||
msgid "Curious"
 | 
					msgid "Curious"
 | 
				
			||||||
msgstr "Curieux⸱euse"
 | 
					msgstr "Curieux⸱euse"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:660
 | 
					#: sith/settings.py:662
 | 
				
			||||||
msgid "A new poster needs to be moderated"
 | 
					msgid "A new poster needs to be moderated"
 | 
				
			||||||
msgstr "Une nouvelle affiche a besoin d'être modérée"
 | 
					msgstr "Une nouvelle affiche a besoin d'être modérée"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:661
 | 
					#: sith/settings.py:663
 | 
				
			||||||
msgid "A new mailing list needs to be moderated"
 | 
					msgid "A new mailing list needs to be moderated"
 | 
				
			||||||
msgstr "Une nouvelle mailing list a besoin d'être modérée"
 | 
					msgstr "Une nouvelle mailing list a besoin d'être modérée"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:664
 | 
					#: sith/settings.py:666
 | 
				
			||||||
msgid "A new pedagogy comment has been signaled for moderation"
 | 
					msgid "A new pedagogy comment has been signaled for moderation"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Un nouveau commentaire de la pédagogie a été signalé pour la modération"
 | 
					"Un nouveau commentaire de la pédagogie a été signalé pour la modération"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:666
 | 
					#: sith/settings.py:668
 | 
				
			||||||
#, python-format
 | 
					#, python-format
 | 
				
			||||||
msgid "There are %s fresh news to be moderated"
 | 
					msgid "There are %s fresh news to be moderated"
 | 
				
			||||||
msgstr "Il y a %s nouvelles toutes fraîches à modérer"
 | 
					msgstr "Il y a %s nouvelles toutes fraîches à modérer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:667
 | 
					#: sith/settings.py:669
 | 
				
			||||||
msgid "New files to be moderated"
 | 
					msgid "New files to be moderated"
 | 
				
			||||||
msgstr "Nouveaux fichiers à modérer"
 | 
					msgstr "Nouveaux fichiers à modérer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:668
 | 
					#: sith/settings.py:670
 | 
				
			||||||
#, python-format
 | 
					#, python-format
 | 
				
			||||||
msgid "There are %s pictures to be moderated in the SAS"
 | 
					msgid "There are %s pictures to be moderated in the SAS"
 | 
				
			||||||
msgstr "Il y a %s photos à modérer dans le SAS"
 | 
					msgstr "Il y a %s photos à modérer dans le SAS"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:669
 | 
					#: sith/settings.py:671
 | 
				
			||||||
msgid "You've been identified on some pictures"
 | 
					msgid "You've been identified on some pictures"
 | 
				
			||||||
msgstr "Vous avez été identifié sur des photos"
 | 
					msgstr "Vous avez été identifié sur des photos"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:670
 | 
					#: sith/settings.py:672
 | 
				
			||||||
#, python-format
 | 
					#, python-format
 | 
				
			||||||
msgid "You just refilled of %s €"
 | 
					msgid "You just refilled of %s €"
 | 
				
			||||||
msgstr "Vous avez rechargé votre compte de %s€"
 | 
					msgstr "Vous avez rechargé votre compte de %s€"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:671
 | 
					#: sith/settings.py:673
 | 
				
			||||||
#, python-format
 | 
					#, python-format
 | 
				
			||||||
msgid "You just bought %s"
 | 
					msgid "You just bought %s"
 | 
				
			||||||
msgstr "Vous avez acheté %s"
 | 
					msgstr "Vous avez acheté %s"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:672
 | 
					#: sith/settings.py:674
 | 
				
			||||||
msgid "You have a notification"
 | 
					msgid "You have a notification"
 | 
				
			||||||
msgstr "Vous avez une notification"
 | 
					msgstr "Vous avez une notification"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:684
 | 
					#: sith/settings.py:686
 | 
				
			||||||
msgid "Success!"
 | 
					msgid "Success!"
 | 
				
			||||||
msgstr "Succès !"
 | 
					msgstr "Succès !"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:685
 | 
					#: sith/settings.py:687
 | 
				
			||||||
msgid "Fail!"
 | 
					msgid "Fail!"
 | 
				
			||||||
msgstr "Échec !"
 | 
					msgstr "Échec !"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:686
 | 
					#: sith/settings.py:688
 | 
				
			||||||
msgid "You successfully posted an article in the Weekmail"
 | 
					msgid "You successfully posted an article in the Weekmail"
 | 
				
			||||||
msgstr "Article posté avec succès dans le Weekmail"
 | 
					msgstr "Article posté avec succès dans le Weekmail"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:687
 | 
					#: sith/settings.py:689
 | 
				
			||||||
msgid "You successfully edited an article in the Weekmail"
 | 
					msgid "You successfully edited an article in the Weekmail"
 | 
				
			||||||
msgstr "Article édité avec succès dans le Weekmail"
 | 
					msgstr "Article édité avec succès dans le Weekmail"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:688
 | 
					#: sith/settings.py:690
 | 
				
			||||||
msgid "You successfully sent the Weekmail"
 | 
					msgid "You successfully sent the Weekmail"
 | 
				
			||||||
msgstr "Weekmail envoyé avec succès"
 | 
					msgstr "Weekmail envoyé avec succès"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: sith/settings.py:696
 | 
					#: sith/settings.py:698
 | 
				
			||||||
msgid "AE tee-shirt"
 | 
					msgid "AE tee-shirt"
 | 
				
			||||||
msgstr "Tee-shirt AE"
 | 
					msgstr "Tee-shirt AE"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -5828,27 +5820,14 @@ msgstr "Vous ne pouvez pas cotiser plusieurs fois pour la même période"
 | 
				
			|||||||
msgid "Subscription created for %(user)s"
 | 
					msgid "Subscription created for %(user)s"
 | 
				
			||||||
msgstr "Cotisation créée pour %(user)s"
 | 
					msgstr "Cotisation créée pour %(user)s"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: subscription/templates/subscription/fragments/creation_success.jinja:8
 | 
					#: subscription/templates/subscription/fragments/creation_success.jinja:19
 | 
				
			||||||
#, python-format
 | 
					 | 
				
			||||||
msgid ""
 | 
					 | 
				
			||||||
"%(user)s received its new %(type)s subscription. It will be active until "
 | 
					 | 
				
			||||||
"%(end)s included."
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
"%(user)s a reçu sa nouvelle cotisaton %(type)s. Elle sert active jusqu'au "
 | 
					 | 
				
			||||||
"%(end)s inclu."
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: subscription/templates/subscription/fragments/creation_success.jinja:16
 | 
					 | 
				
			||||||
msgid "Go to user profile"
 | 
					msgid "Go to user profile"
 | 
				
			||||||
msgstr "Voir le profil de l'utilisateur"
 | 
					msgstr "Voir le profil de l'utilisateur"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: subscription/templates/subscription/fragments/creation_success.jinja:24
 | 
					#: subscription/templates/subscription/fragments/creation_success.jinja:27
 | 
				
			||||||
msgid "Create another subscription"
 | 
					msgid "Create another subscription"
 | 
				
			||||||
msgstr "Créer une nouvelle cotisation"
 | 
					msgstr "Créer une nouvelle cotisation"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: subscription/templates/subscription/subscription.jinja
 | 
					 | 
				
			||||||
msgid "Existing member"
 | 
					 | 
				
			||||||
msgstr "Membre existant"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#: subscription/templates/subscription/stats.jinja:27
 | 
					#: subscription/templates/subscription/stats.jinja:27
 | 
				
			||||||
msgid "Total subscriptions"
 | 
					msgid "Total subscriptions"
 | 
				
			||||||
msgstr "Cotisations totales"
 | 
					msgstr "Cotisations totales"
 | 
				
			||||||
@@ -5857,6 +5836,10 @@ msgstr "Cotisations totales"
 | 
				
			|||||||
msgid "Subscriptions by type"
 | 
					msgid "Subscriptions by type"
 | 
				
			||||||
msgstr "Cotisations par type"
 | 
					msgstr "Cotisations par type"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: subscription/templates/subscription/subscription.jinja:38
 | 
				
			||||||
 | 
					msgid "Existing member"
 | 
				
			||||||
 | 
					msgstr "Membre existant"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: trombi/models.py:55
 | 
					#: trombi/models.py:55
 | 
				
			||||||
msgid "subscription deadline"
 | 
					msgid "subscription deadline"
 | 
				
			||||||
msgstr "fin des inscriptions"
 | 
					msgstr "fin des inscriptions"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
 | 
					from django.core.cache import cache
 | 
				
			||||||
from django.db import transaction
 | 
					from django.db import transaction
 | 
				
			||||||
from django.test import TestCase
 | 
					from django.test import TestCase
 | 
				
			||||||
from django.urls import reverse
 | 
					from django.urls import reverse
 | 
				
			||||||
from model_bakery import baker
 | 
					from model_bakery import baker
 | 
				
			||||||
from model_bakery.recipe import Recipe
 | 
					from model_bakery.recipe import Recipe
 | 
				
			||||||
from pytest_django.asserts import assertNumQueries
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from core.baker_recipes import old_subscriber_user, subscriber_user
 | 
					from core.baker_recipes import old_subscriber_user, subscriber_user
 | 
				
			||||||
from core.models import RealGroup, SithFile, User
 | 
					from core.models import RealGroup, SithFile, User
 | 
				
			||||||
@@ -128,9 +128,11 @@ class TestPictureSearch(TestSas):
 | 
				
			|||||||
    def test_num_queries(self):
 | 
					    def test_num_queries(self):
 | 
				
			||||||
        """Test that the number of queries is stable."""
 | 
					        """Test that the number of queries is stable."""
 | 
				
			||||||
        self.client.force_login(subscriber_user.make())
 | 
					        self.client.force_login(subscriber_user.make())
 | 
				
			||||||
        with assertNumQueries(5):
 | 
					        cache.clear()
 | 
				
			||||||
 | 
					        with self.assertNumQueries(7):
 | 
				
			||||||
 | 
					            # 2 requests to create the session
 | 
				
			||||||
            # 1 request to fetch the user from the db
 | 
					            # 1 request to fetch the user from the db
 | 
				
			||||||
            # 2 requests to check the user permissions
 | 
					            # 2 requests to check the user permissions, depends on the db engine
 | 
				
			||||||
            # 1 request to fetch the pictures
 | 
					            # 1 request to fetch the pictures
 | 
				
			||||||
            # 1 request to count the total number of items in the pagination
 | 
					            # 1 request to count the total number of items in the pagination
 | 
				
			||||||
            self.client.get(self.url)
 | 
					            self.client.get(self.url)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user