mirror of
https://github.com/ae-utbm/sith.git
synced 2024-11-25 02:24:26 +00:00
Make StudentCard unique by customer
This commit is contained in:
parent
1f6ad0a629
commit
74df077b31
@ -36,34 +36,31 @@
|
|||||||
|
|
||||||
|
|
||||||
{% if profile.customer %}
|
{% if profile.customer %}
|
||||||
<h3>{% trans %}Student cards{% endtrans %}</h3>
|
<h3>{% trans %}Student card{% endtrans %}</h3>
|
||||||
|
|
||||||
{% if profile.customer.student_cards.exists() %}
|
{% if profile.customer.student_card %}
|
||||||
<ul class="student-cards">
|
<span class="student-cards">
|
||||||
{% for card in profile.customer.student_cards.all() %}
|
{% trans %}Registered{% endtrans %} <i class="fa fa-check"></i> -
|
||||||
<li>
|
<a href="{{ url('counter:delete_student_card', customer_id=profile.customer.pk) }}">
|
||||||
{{ card.uid }}
|
{% trans %}Delete{% endtrans %}
|
||||||
-
|
</a>
|
||||||
<a href="{{ url('counter:delete_student_card', customer_id=profile.customer.pk, card_id=card.id) }}">
|
</span>
|
||||||
{% trans %}Delete{% endtrans %}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<em class="no-cards">{% trans %}No student card registered.{% endtrans %}</em>
|
<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>
|
||||||
|
<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 %}
|
{% 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 %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -52,9 +52,7 @@ class StudentCardForm(forms.ModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = StudentCard
|
model = StudentCard
|
||||||
fields = ["uid"]
|
fields = ["uid"]
|
||||||
widgets = {
|
widgets = {"uid": NFCTextInput}
|
||||||
"uid": NFCTextInput,
|
|
||||||
}
|
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
cleaned_data = super().clean()
|
cleaned_data = super().clean()
|
||||||
|
52
counter/migrations/0025_alter_studentcard_customer.py
Normal file
52
counter/migrations/0025_alter_studentcard_customer.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Generated by Django 4.2.16 on 2024-11-15 12:34
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from operator import attrgetter
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
from django.db.models import Count
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from django.db.backends.postgresql.schema import DatabaseSchemaEditor
|
||||||
|
from django.db.migrations.state import StateApps
|
||||||
|
|
||||||
|
|
||||||
|
def delete_duplicates(apps: StateApps, schema_editor: DatabaseSchemaEditor):
|
||||||
|
"""Delete cards of users with more than one student cards.
|
||||||
|
|
||||||
|
For all users who have more than one registered student card, all
|
||||||
|
the cards except the last one are deleted.
|
||||||
|
"""
|
||||||
|
Customer = apps.get_model("counter", "Customer")
|
||||||
|
StudentCard = apps.get_model("counter", "StudentCard")
|
||||||
|
customers = (
|
||||||
|
Customer.objects.annotate(nb_cards=Count("student_cards"))
|
||||||
|
.filter(nb_cards__gt=1)
|
||||||
|
.prefetch_related("student_cards")
|
||||||
|
)
|
||||||
|
to_delete = [
|
||||||
|
card.id
|
||||||
|
for customer in customers
|
||||||
|
for card in sorted(customer.student_cards.all(), key=attrgetter("id"))[:-1]
|
||||||
|
]
|
||||||
|
StudentCard.objects.filter(id__in=to_delete).delete()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [("counter", "0024_accountdump_accountdump_unique_ongoing_dump")]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(delete_duplicates, migrations.RunPython.noop),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="studentcard",
|
||||||
|
name="customer",
|
||||||
|
field=models.OneToOneField(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="student_card",
|
||||||
|
to="counter.customer",
|
||||||
|
verbose_name="student card",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
@ -1132,12 +1132,10 @@ class StudentCard(models.Model):
|
|||||||
uid = models.CharField(
|
uid = models.CharField(
|
||||||
_("uid"), max_length=UID_SIZE, unique=True, validators=[MinLengthValidator(4)]
|
_("uid"), max_length=UID_SIZE, unique=True, validators=[MinLengthValidator(4)]
|
||||||
)
|
)
|
||||||
customer = models.ForeignKey(
|
customer = models.OneToOneField(
|
||||||
Customer,
|
Customer,
|
||||||
related_name="student_cards",
|
related_name="student_card",
|
||||||
verbose_name=_("student cards"),
|
verbose_name=_("student card"),
|
||||||
null=False,
|
|
||||||
blank=False,
|
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1145,7 +1143,7 @@ class StudentCard(models.Model):
|
|||||||
return self.uid
|
return self.uid
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_valid(uid):
|
def is_valid(uid: str):
|
||||||
return (
|
return (
|
||||||
(uid.isupper() or uid.isnumeric())
|
(uid.isupper() or uid.isnumeric())
|
||||||
and len(uid) == StudentCard.UID_SIZE
|
and len(uid) == StudentCard.UID_SIZE
|
||||||
|
@ -29,26 +29,26 @@
|
|||||||
{{ 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) }}">
|
<h6>{% trans %}Student card{% endtrans %}</h6>
|
||||||
{% csrf_token %}
|
{% if student_card %}
|
||||||
<input type="hidden" name="action" value="add_student_card">
|
<p>
|
||||||
{% trans %}Add a student card{% endtrans %}
|
{% trans %}Registered{% endtrans %} <i class="fa fa-check"></i> -
|
||||||
{{ student_card_input.student_card_uid }}
|
<a href="{{ url('counter:delete_student_card', customer_id=customer.pk) }}">
|
||||||
{% if request.session['not_valid_student_card_uid'] %}
|
{% trans %}Delete{% endtrans %}
|
||||||
<p><strong>{% trans %}This is not a valid student card UID{% endtrans %}</strong></p>
|
</a>
|
||||||
{% endif %}
|
</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 }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
{% trans %}No card registered{% endtrans %}
|
{% trans %}No card registered{% endtrans %}
|
||||||
|
<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>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import itertools
|
||||||
import json
|
import json
|
||||||
import string
|
import string
|
||||||
|
|
||||||
@ -188,216 +189,102 @@ class TestStudentCard(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_add_student_card_from_counter(self):
|
def test_add_student_card_from_counter(self):
|
||||||
# Test card with mixed letters and numbers
|
for uid in ["8B90734A802A8F", "ABCAAAFAAFAAAB", "15248196326518"]:
|
||||||
response = self.client.post(
|
self.sli.customer.student_card.delete()
|
||||||
reverse(
|
self.client.post(
|
||||||
"counter:click",
|
reverse(
|
||||||
kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
|
"counter:click",
|
||||||
),
|
kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
|
||||||
{"student_card_uid": "8B90734A802A8F", "action": "add_student_card"},
|
),
|
||||||
)
|
{"student_card_uid": uid, "action": "add_student_card"},
|
||||||
self.assertContains(response, text="8B90734A802A8F")
|
)
|
||||||
|
self.sli.customer.refresh_from_db()
|
||||||
# Test card with only numbers
|
assert self.sli.customer.student_card.uid == uid
|
||||||
response = self.client.post(
|
|
||||||
reverse(
|
|
||||||
"counter:click",
|
|
||||||
kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
|
|
||||||
),
|
|
||||||
{"student_card_uid": "04786547890123", "action": "add_student_card"},
|
|
||||||
)
|
|
||||||
self.assertContains(response, text="04786547890123")
|
|
||||||
|
|
||||||
# Test card with only letters
|
|
||||||
response = self.client.post(
|
|
||||||
reverse(
|
|
||||||
"counter:click",
|
|
||||||
kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
|
|
||||||
),
|
|
||||||
{"student_card_uid": "ABCAAAFAAFAAAB", "action": "add_student_card"},
|
|
||||||
)
|
|
||||||
self.assertContains(response, 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(
|
self.sli.customer.student_card.delete()
|
||||||
reverse(
|
# too short, then too long, then containing lowercase, then spaces
|
||||||
"counter:click",
|
for uid in ["8B90734A802A8", "8B90734A802A8FA", "8b90734a802a9f", " " * 14]:
|
||||||
kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
|
response = self.client.post(
|
||||||
),
|
reverse(
|
||||||
{"student_card_uid": "8B90734A802A8", "action": "add_student_card"},
|
"counter:click",
|
||||||
)
|
kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
|
||||||
self.assertContains(
|
),
|
||||||
response, text="Ce n'est pas un UID de carte étudiante valide"
|
{"student_card_uid": uid, "action": "add_student_card"},
|
||||||
)
|
)
|
||||||
|
self.assertContains(
|
||||||
# UID too long
|
response, text="Ce n'est pas un UID de carte étudiante valide"
|
||||||
response = self.client.post(
|
)
|
||||||
reverse(
|
self.sli.customer.refresh_from_db()
|
||||||
"counter:click",
|
assert not hasattr(self.sli.customer, "student_card")
|
||||||
kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
|
|
||||||
),
|
|
||||||
{"student_card_uid": "8B90734A802A8FA", "action": "add_student_card"},
|
|
||||||
)
|
|
||||||
self.assertContains(
|
|
||||||
response, text="Ce n'est pas un UID de carte étudiante valide"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Test with already existing card
|
|
||||||
response = self.client.post(
|
|
||||||
reverse(
|
|
||||||
"counter:click",
|
|
||||||
kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
|
|
||||||
),
|
|
||||||
{"student_card_uid": "9A89B82018B0A0", "action": "add_student_card"},
|
|
||||||
)
|
|
||||||
self.assertContains(
|
|
||||||
response, text="Ce n'est pas un UID de carte étudiante valide"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Test with lowercase
|
|
||||||
response = self.client.post(
|
|
||||||
reverse(
|
|
||||||
"counter:click",
|
|
||||||
kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
|
|
||||||
),
|
|
||||||
{"student_card_uid": "8b90734a802a9f", "action": "add_student_card"},
|
|
||||||
)
|
|
||||||
self.assertContains(
|
|
||||||
response, text="Ce n'est pas un UID de carte étudiante valide"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Test with white spaces
|
|
||||||
response = self.client.post(
|
|
||||||
reverse(
|
|
||||||
"counter:click",
|
|
||||||
kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
|
|
||||||
),
|
|
||||||
{"student_card_uid": " ", "action": "add_student_card"},
|
|
||||||
)
|
|
||||||
self.assertContains(
|
|
||||||
response, text="Ce n'est pas un UID de carte étudiante valide"
|
|
||||||
)
|
|
||||||
|
|
||||||
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.sli)
|
||||||
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.sli.customer.pk,
|
|
||||||
"card_id": self.sli.customer.student_cards.first().id,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
assert not self.sli.customer.student_cards.exists()
|
self.sli.customer.refresh_from_db()
|
||||||
|
assert not hasattr(self.sli.customer, "student_card")
|
||||||
|
|
||||||
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.skia)
|
||||||
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.sli.customer.pk,
|
|
||||||
"card_id": self.sli.customer.student_cards.first().id,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
assert not self.sli.customer.student_cards.exists()
|
self.sli.customer.refresh_from_db()
|
||||||
|
assert not hasattr(self.sli.customer, "student_card")
|
||||||
|
|
||||||
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)
|
||||||
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.sli.customer.pk,
|
|
||||||
"card_id": self.sli.customer.student_cards.first().id,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
assert not self.sli.customer.student_cards.exists()
|
self.sli.customer.refresh_from_db()
|
||||||
|
assert not hasattr(self.sli.customer, "student_card")
|
||||||
|
|
||||||
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.krophil)
|
||||||
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.sli.customer.pk,
|
|
||||||
"card_id": self.sli.customer.student_cards.first().id,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
assert response.status_code == 403
|
assert response.status_code == 403
|
||||||
assert self.sli.customer.student_cards.exists()
|
self.sli.customer.refresh_from_db()
|
||||||
|
assert hasattr(self.sli.customer, "student_card")
|
||||||
|
|
||||||
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)
|
users = [self.sli, self.skia, self.root]
|
||||||
self.client.post(
|
uids = ["8B90734A802A8F", "ABCAAAFAAFAAAB", "15248196326518"]
|
||||||
reverse(
|
for user, uid in itertools.product(users, uids):
|
||||||
"counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
|
self.sli.customer.student_card.delete()
|
||||||
),
|
self.client.force_login(user)
|
||||||
{"uid": "8B90734A802A8F"},
|
self.client.post(
|
||||||
)
|
reverse(
|
||||||
|
"counter:add_student_card",
|
||||||
|
kwargs={"customer_id": self.sli.customer.pk},
|
||||||
|
),
|
||||||
|
{"uid": uid},
|
||||||
|
)
|
||||||
|
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
reverse("core:user_prefs", kwargs={"user_id": self.sli.id})
|
reverse("core:user_prefs", kwargs={"user_id": self.sli.id})
|
||||||
)
|
)
|
||||||
self.assertContains(response, text="8B90734A802A8F")
|
self.sli.customer.refresh_from_db()
|
||||||
|
assert self.sli.customer.student_card.uid == uid
|
||||||
# Test with board member
|
self.assertContains(response, text="Enregistré")
|
||||||
self.client.force_login(self.skia)
|
|
||||||
self.client.post(
|
|
||||||
reverse(
|
|
||||||
"counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
|
|
||||||
),
|
|
||||||
{"uid": "8B90734A802A8A"},
|
|
||||||
)
|
|
||||||
|
|
||||||
response = self.client.get(
|
|
||||||
reverse("core:user_prefs", kwargs={"user_id": self.sli.id})
|
|
||||||
)
|
|
||||||
self.assertContains(response, text="8B90734A802A8A")
|
|
||||||
|
|
||||||
# Test card with only numbers
|
|
||||||
self.client.post(
|
|
||||||
reverse(
|
|
||||||
"counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
|
|
||||||
),
|
|
||||||
{"uid": "04786547890123"},
|
|
||||||
)
|
|
||||||
response = self.client.get(
|
|
||||||
reverse("core:user_prefs", kwargs={"user_id": self.sli.id})
|
|
||||||
)
|
|
||||||
self.assertContains(response, text="04786547890123")
|
|
||||||
|
|
||||||
# Test card with only letters
|
|
||||||
self.client.post(
|
|
||||||
reverse(
|
|
||||||
"counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
|
|
||||||
),
|
|
||||||
{"uid": "ABCAAAFAAFAAAB"},
|
|
||||||
)
|
|
||||||
response = self.client.get(
|
|
||||||
reverse("core:user_prefs", kwargs={"user_id": self.sli.id})
|
|
||||||
)
|
|
||||||
self.assertContains(response, text="ABCAAAFAAFAAAB")
|
|
||||||
|
|
||||||
# Test with root
|
|
||||||
self.client.force_login(self.root)
|
|
||||||
self.client.post(
|
|
||||||
reverse(
|
|
||||||
"counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
|
|
||||||
),
|
|
||||||
{"uid": "8B90734A802A8B"},
|
|
||||||
)
|
|
||||||
|
|
||||||
response = self.client.get(
|
|
||||||
reverse("core:user_prefs", kwargs={"user_id": self.sli.id})
|
|
||||||
)
|
|
||||||
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.sli)
|
||||||
|
@ -74,7 +74,7 @@ urlpatterns = [
|
|||||||
name="add_student_card",
|
name="add_student_card",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"customer/<int:customer_id>/card/delete/<int:card_id>/",
|
"customer/<int:customer_id>/card/delete",
|
||||||
StudentCardDeleteView.as_view(),
|
StudentCardDeleteView.as_view(),
|
||||||
name="delete_student_card",
|
name="delete_student_card",
|
||||||
),
|
),
|
||||||
|
@ -111,16 +111,23 @@ class StudentCardDeleteView(DeleteView, CanEditMixin):
|
|||||||
|
|
||||||
model = StudentCard
|
model = StudentCard
|
||||||
template_name = "core/delete_confirm.jinja"
|
template_name = "core/delete_confirm.jinja"
|
||||||
pk_url_kwarg = "card_id"
|
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
self.customer = get_object_or_404(Customer, pk=kwargs["customer_id"])
|
self.customer = get_object_or_404(Customer, pk=kwargs["customer_id"])
|
||||||
return super().dispatch(request, *args, **kwargs)
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_object(self, queryset=None):
|
||||||
|
if not hasattr(self.customer, "student_card"):
|
||||||
|
raise Http404(
|
||||||
|
_(
|
||||||
|
"The customer %s has no registered student card",
|
||||||
|
self.customer.user.get_full_name(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return self.customer.student_card
|
||||||
|
|
||||||
def get_success_url(self, **kwargs):
|
def get_success_url(self, **kwargs):
|
||||||
return reverse_lazy(
|
return reverse("core:user_prefs", kwargs={"user_id": self.customer.user_id})
|
||||||
"core:user_prefs", kwargs={"user_id": self.customer.user.pk}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class CounterTabsMixin(TabedViewMixin):
|
class CounterTabsMixin(TabedViewMixin):
|
||||||
@ -627,7 +634,7 @@ 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"] = getattr(self.customer, "student_card", None)
|
||||||
kwargs["student_card_input"] = NFCCardForm()
|
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()
|
||||||
@ -1527,11 +1534,10 @@ class StudentCardFormView(FormView):
|
|||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
data = form.clean()
|
data = form.clean()
|
||||||
res = super(FormView, self).form_valid(form)
|
StudentCard.objects.update_or_create(
|
||||||
StudentCard(customer=self.customer, uid=data["uid"]).save()
|
customer=self.customer, defaults={"uid": data["uid"]}
|
||||||
return res
|
)
|
||||||
|
return super(FormView, self).form_valid(form)
|
||||||
|
|
||||||
def get_success_url(self, **kwargs):
|
def get_success_url(self, **kwargs):
|
||||||
return reverse_lazy(
|
return reverse("core:user_prefs", kwargs={"user_id": self.customer.user_id})
|
||||||
"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-14 10:26+0100\n"
|
"POT-Creation-Date: 2024-11-15 13:03+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"
|
||||||
@ -369,7 +369,8 @@ 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
|
#: core/templates/core/user_preferences.jinja:45
|
||||||
|
#: counter/templates/counter/counter_click.jinja:37
|
||||||
#: 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:187
|
#: election/templates/election/election_detail.jinja:187
|
||||||
@ -650,7 +651,7 @@ 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 counter/views.py:957
|
||||||
#: pedagogy/templates/pedagogy/moderation.jinja:13
|
#: 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
|
||||||
@ -771,7 +772,7 @@ 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
|
#: core/templates/core/user_preferences.jinja:61
|
||||||
#: 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/subscription.jinja:25
|
#: subscription/templates/subscription/subscription.jinja:25
|
||||||
@ -951,11 +952,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:201
|
||||||
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:204
|
||||||
#: election/views.py:170 subscription/views.py:38
|
#: election/views.py:170 subscription/views.py:38
|
||||||
msgid "End date"
|
msgid "End date"
|
||||||
msgstr "Date de fin"
|
msgstr "Date de fin"
|
||||||
@ -963,15 +964,15 @@ 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.py:139
|
||||||
msgid "Counter"
|
msgid "Counter"
|
||||||
msgstr "Comptoir"
|
msgstr "Comptoir"
|
||||||
|
|
||||||
#: club/forms.py:163 counter/views.py:683
|
#: club/forms.py:163 counter/views.py:685
|
||||||
msgid "Products"
|
msgid "Products"
|
||||||
msgstr "Produits"
|
msgstr "Produits"
|
||||||
|
|
||||||
#: club/forms.py:168 counter/views.py:688
|
#: club/forms.py:168 counter/views.py:690
|
||||||
msgid "Archived products"
|
msgid "Archived products"
|
||||||
msgstr "Produits archivés"
|
msgstr "Produits archivés"
|
||||||
|
|
||||||
@ -3041,11 +3042,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.py:710
|
||||||
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:634
|
||||||
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"
|
||||||
|
|
||||||
@ -3295,14 +3296,20 @@ 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:39
|
||||||
msgid "Student cards"
|
#: counter/templates/counter/counter_click.jinja:32
|
||||||
msgstr "Cartes étudiante"
|
msgid "Student card"
|
||||||
|
msgstr "Carte étudiante"
|
||||||
|
|
||||||
#: core/templates/core/user_preferences.jinja:54
|
#: core/templates/core/user_preferences.jinja:43
|
||||||
|
#: counter/templates/counter/counter_click.jinja:35
|
||||||
|
msgid "Registered"
|
||||||
|
msgstr "Enregistré"
|
||||||
|
|
||||||
|
#: core/templates/core/user_preferences.jinja:49
|
||||||
msgid "No student card registered."
|
msgid "No student card registered."
|
||||||
msgstr "Aucune carte étudiante enregistrée."
|
msgstr "Aucune carte étudiante enregistrée."
|
||||||
|
|
||||||
#: core/templates/core/user_preferences.jinja:56
|
#: core/templates/core/user_preferences.jinja:51
|
||||||
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"
|
||||||
@ -3376,8 +3383,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:174
|
||||||
#: counter/views.py:678
|
#: counter/views.py:680
|
||||||
msgid "Counters"
|
msgid "Counters"
|
||||||
msgstr "Comptoirs"
|
msgstr "Comptoirs"
|
||||||
|
|
||||||
@ -3394,12 +3401,12 @@ 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.py:700
|
||||||
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.py:705
|
||||||
msgid "Invoices call"
|
msgid "Invoices call"
|
||||||
msgstr "Appels à facture"
|
msgstr "Appels à facture"
|
||||||
|
|
||||||
@ -3547,7 +3554,7 @@ msgstr "Parrain / Marraine"
|
|||||||
msgid "Godchild"
|
msgid "Godchild"
|
||||||
msgstr "Fillot / Fillote"
|
msgstr "Fillot / Fillote"
|
||||||
|
|
||||||
#: core/views/forms.py:311 counter/forms.py:82 trombi/views.py:151
|
#: core/views/forms.py:311 counter/forms.py:80 trombi/views.py:151
|
||||||
msgid "Select user"
|
msgid "Select user"
|
||||||
msgstr "Choisir un utilisateur"
|
msgstr "Choisir un utilisateur"
|
||||||
|
|
||||||
@ -3600,11 +3607,11 @@ 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é"
|
||||||
|
|
||||||
@ -3632,7 +3639,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.py:263
|
||||||
msgid "Not enough money"
|
msgid "Not enough money"
|
||||||
msgstr "Solde insuffisant"
|
msgstr "Solde insuffisant"
|
||||||
|
|
||||||
@ -3858,10 +3865,6 @@ msgstr "secret"
|
|||||||
msgid "uid"
|
msgid "uid"
|
||||||
msgstr "uid"
|
msgstr "uid"
|
||||||
|
|
||||||
#: counter/models.py:1138
|
|
||||||
msgid "student cards"
|
|
||||||
msgstr "cartes étudiante"
|
|
||||||
|
|
||||||
#: counter/templates/counter/account_dump_warning_mail.jinja:1
|
#: counter/templates/counter/account_dump_warning_mail.jinja:1
|
||||||
msgid "Hello"
|
msgid "Hello"
|
||||||
msgstr "Bonjour"
|
msgstr "Bonjour"
|
||||||
@ -3963,7 +3966,7 @@ msgstr "Liste des relevés de caisse"
|
|||||||
msgid "Theoric sums"
|
msgid "Theoric sums"
|
||||||
msgstr "Sommes théoriques"
|
msgstr "Sommes théoriques"
|
||||||
|
|
||||||
#: counter/templates/counter/cash_summary_list.jinja:36 counter/views.py:956
|
#: counter/templates/counter/cash_summary_list.jinja:36 counter/views.py:958
|
||||||
msgid "Emptied"
|
msgid "Emptied"
|
||||||
msgstr "Coffre vidé"
|
msgstr "Coffre vidé"
|
||||||
|
|
||||||
@ -3975,15 +3978,19 @@ 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:41
|
||||||
|
msgid "No card registered"
|
||||||
|
msgstr "Aucune carte enregistrée"
|
||||||
|
|
||||||
|
#: counter/templates/counter/counter_click.jinja:45
|
||||||
msgid "Add a student card"
|
msgid "Add a student card"
|
||||||
msgstr "Ajouter une carte étudiante"
|
msgstr "Ajouter une carte étudiante"
|
||||||
|
|
||||||
#: counter/templates/counter/counter_click.jinja:38
|
#: counter/templates/counter/counter_click.jinja:48
|
||||||
msgid "This is not a valid student card UID"
|
msgid "This is not a valid student card UID"
|
||||||
msgstr "Ce n'est pas un UID de carte étudiante valide"
|
msgstr "Ce n'est pas un UID de carte étudiante valide"
|
||||||
|
|
||||||
#: counter/templates/counter/counter_click.jinja:40
|
#: counter/templates/counter/counter_click.jinja:50
|
||||||
#: counter/templates/counter/counter_click.jinja:67
|
#: counter/templates/counter/counter_click.jinja:67
|
||||||
#: counter/templates/counter/counter_click.jinja:132
|
#: counter/templates/counter/counter_click.jinja:132
|
||||||
#: counter/templates/counter/invoices_call.jinja:16
|
#: counter/templates/counter/invoices_call.jinja:16
|
||||||
@ -3994,14 +4001,6 @@ 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
|
|
||||||
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
|
#: counter/templates/counter/counter_click.jinja:56
|
||||||
#: launderette/templates/launderette/launderette_admin.jinja:8
|
#: launderette/templates/launderette/launderette_admin.jinja:8
|
||||||
msgid "Selling"
|
msgid "Selling"
|
||||||
@ -4189,101 +4188,101 @@ 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.py:149
|
||||||
msgid "Cash summary"
|
msgid "Cash summary"
|
||||||
msgstr "Relevé de caisse"
|
msgstr "Relevé de caisse"
|
||||||
|
|
||||||
#: counter/views.py:156
|
#: counter/views.py:158
|
||||||
msgid "Last operations"
|
msgid "Last operations"
|
||||||
msgstr "Dernières opérations"
|
msgstr "Dernières opérations"
|
||||||
|
|
||||||
#: counter/views.py:203
|
#: counter/views.py:205
|
||||||
msgid "Bad credentials"
|
msgid "Bad credentials"
|
||||||
msgstr "Mauvais identifiants"
|
msgstr "Mauvais identifiants"
|
||||||
|
|
||||||
#: counter/views.py:205
|
#: counter/views.py:207
|
||||||
msgid "User is not barman"
|
msgid "User is not barman"
|
||||||
msgstr "L'utilisateur n'est pas barman."
|
msgstr "L'utilisateur n'est pas barman."
|
||||||
|
|
||||||
#: counter/views.py:210
|
#: counter/views.py:212
|
||||||
msgid "Bad location, someone is already logged in somewhere else"
|
msgid "Bad location, someone is already logged in somewhere else"
|
||||||
msgstr "Mauvais comptoir, quelqu'un est déjà connecté ailleurs"
|
msgstr "Mauvais comptoir, quelqu'un est déjà connecté ailleurs"
|
||||||
|
|
||||||
#: counter/views.py:252
|
#: counter/views.py:254
|
||||||
msgid "Too young for that product"
|
msgid "Too young for that product"
|
||||||
msgstr "Trop jeune pour ce produit"
|
msgstr "Trop jeune pour ce produit"
|
||||||
|
|
||||||
#: counter/views.py:255
|
#: counter/views.py:257
|
||||||
msgid "Not allowed for that product"
|
msgid "Not allowed for that product"
|
||||||
msgstr "Non autorisé pour ce produit"
|
msgstr "Non autorisé pour ce produit"
|
||||||
|
|
||||||
#: counter/views.py:258
|
#: counter/views.py:260
|
||||||
msgid "No date of birth provided"
|
msgid "No date of birth provided"
|
||||||
msgstr "Pas de date de naissance renseignée"
|
msgstr "Pas de date de naissance renseignée"
|
||||||
|
|
||||||
#: counter/views.py:546
|
#: counter/views.py:548
|
||||||
msgid "You have not enough money to buy all the basket"
|
msgid "You have not enough money to buy all the basket"
|
||||||
msgstr "Vous n'avez pas assez d'argent pour acheter le panier"
|
msgstr "Vous n'avez pas assez d'argent pour acheter le panier"
|
||||||
|
|
||||||
#: counter/views.py:673
|
#: counter/views.py:675
|
||||||
msgid "Counter administration"
|
msgid "Counter administration"
|
||||||
msgstr "Administration des comptoirs"
|
msgstr "Administration des comptoirs"
|
||||||
|
|
||||||
#: counter/views.py:693
|
#: counter/views.py:695
|
||||||
msgid "Product types"
|
msgid "Product types"
|
||||||
msgstr "Types de produit"
|
msgstr "Types de produit"
|
||||||
|
|
||||||
#: counter/views.py:913
|
#: counter/views.py:915
|
||||||
msgid "10 cents"
|
msgid "10 cents"
|
||||||
msgstr "10 centimes"
|
msgstr "10 centimes"
|
||||||
|
|
||||||
#: counter/views.py:914
|
#: counter/views.py:916
|
||||||
msgid "20 cents"
|
msgid "20 cents"
|
||||||
msgstr "20 centimes"
|
msgstr "20 centimes"
|
||||||
|
|
||||||
#: counter/views.py:915
|
#: counter/views.py:917
|
||||||
msgid "50 cents"
|
msgid "50 cents"
|
||||||
msgstr "50 centimes"
|
msgstr "50 centimes"
|
||||||
|
|
||||||
#: counter/views.py:916
|
#: counter/views.py:918
|
||||||
msgid "1 euro"
|
msgid "1 euro"
|
||||||
msgstr "1 €"
|
msgstr "1 €"
|
||||||
|
|
||||||
#: counter/views.py:917
|
#: counter/views.py:919
|
||||||
msgid "2 euros"
|
msgid "2 euros"
|
||||||
msgstr "2 €"
|
msgstr "2 €"
|
||||||
|
|
||||||
#: counter/views.py:918
|
#: counter/views.py:920
|
||||||
msgid "5 euros"
|
msgid "5 euros"
|
||||||
msgstr "5 €"
|
msgstr "5 €"
|
||||||
|
|
||||||
#: counter/views.py:919
|
#: counter/views.py:921
|
||||||
msgid "10 euros"
|
msgid "10 euros"
|
||||||
msgstr "10 €"
|
msgstr "10 €"
|
||||||
|
|
||||||
#: counter/views.py:920
|
#: counter/views.py:922
|
||||||
msgid "20 euros"
|
msgid "20 euros"
|
||||||
msgstr "20 €"
|
msgstr "20 €"
|
||||||
|
|
||||||
#: counter/views.py:921
|
#: counter/views.py:923
|
||||||
msgid "50 euros"
|
msgid "50 euros"
|
||||||
msgstr "50 €"
|
msgstr "50 €"
|
||||||
|
|
||||||
#: counter/views.py:923
|
#: counter/views.py:925
|
||||||
msgid "100 euros"
|
msgid "100 euros"
|
||||||
msgstr "100 €"
|
msgstr "100 €"
|
||||||
|
|
||||||
#: counter/views.py:926 counter/views.py:932 counter/views.py:938
|
#: counter/views.py:928 counter/views.py:934 counter/views.py:940
|
||||||
#: counter/views.py:944 counter/views.py:950
|
#: counter/views.py:946 counter/views.py:952
|
||||||
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.py:931 counter/views.py:937 counter/views.py:943
|
||||||
#: counter/views.py:947 counter/views.py:953
|
#: counter/views.py:949 counter/views.py:955
|
||||||
msgid "Check quantity"
|
msgid "Check quantity"
|
||||||
msgstr "Nombre de chèque"
|
msgstr "Nombre de chèque"
|
||||||
|
|
||||||
#: counter/views.py:1473
|
#: counter/views.py:1475
|
||||||
msgid "people(s)"
|
msgid "people(s)"
|
||||||
msgstr "personne(s)"
|
msgstr "personne(s)"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user