mirror of
https://github.com/ae-utbm/sith.git
synced 2024-11-26 02:54:20 +00:00
Merge branch 'nfc_card' into 'master'
Can identify user on counter with student card UID See merge request ae/Sith!172
This commit is contained in:
commit
0f832a2774
@ -48,7 +48,7 @@ from accounting.models import (
|
||||
from core.utils import resize_image
|
||||
from club.models import Club, Membership
|
||||
from subscription.models import Subscription
|
||||
from counter.models import Customer, ProductType, Product, Counter, Selling
|
||||
from counter.models import Customer, ProductType, Product, Counter, Selling, StudentCard
|
||||
from com.models import Sith, Weekmail, News, NewsDate
|
||||
from election.models import Election, Role, Candidature, ElectionList
|
||||
from forum.models import Forum, ForumTopic
|
||||
@ -870,6 +870,7 @@ Welcome to the wiki page!
|
||||
start=s.subscription_start,
|
||||
)
|
||||
s.save()
|
||||
StudentCard(uid="9A89B82018B0A0", customer=sli.customer).save()
|
||||
# Adding subscription for Krophil
|
||||
s = Subscription(
|
||||
member=User.objects.filter(pk=krophil.pk).first(),
|
||||
|
@ -22,6 +22,24 @@
|
||||
<p>{% trans trombi=user.trombi_user.trombi %}You already choose to be in that Trombi: {{ trombi }}.{% endtrans %}
|
||||
<a href="{{ url('trombi:user_tools') }}">{% trans %}Go to my Trombi tools{% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
{% if profile.customer %}
|
||||
<h4>{% trans %}Student cards{% endtrans %}</h4>
|
||||
<p>{% 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 %}</p>
|
||||
<form action="{{ url('counter:add_student_card', customer_id=profile.customer.pk) }}" method="post">
|
||||
{% csrf_token %}
|
||||
{{ student_card_form.as_p() }}
|
||||
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
|
||||
</form>
|
||||
{% if profile.customer.student_cards.exists() %}
|
||||
<ul>
|
||||
{% 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 %}
|
||||
<p>{% trans %}No student cards registered.{% endtrans %}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -64,6 +64,7 @@ from core.views.forms import (
|
||||
)
|
||||
from core.models import User, SithFile, Preferences, Gift
|
||||
from subscription.models import Subscription
|
||||
from counter.views import StudentCardForm
|
||||
from trombi.views import UserTrombiForm
|
||||
|
||||
|
||||
@ -741,6 +742,8 @@ class UserPreferencesView(UserTabsMixin, CanEditMixin, UpdateView):
|
||||
kwargs = super(UserPreferencesView, self).get_context_data(**kwargs)
|
||||
if not hasattr(self.object, "trombi_user"):
|
||||
kwargs["trombi_form"] = UserTrombiForm()
|
||||
if self.object.customer:
|
||||
kwargs["student_card_form"] = StudentCardForm()
|
||||
return kwargs
|
||||
|
||||
|
||||
|
47
counter/migrations/0017_studentcard.py
Normal file
47
counter/migrations/0017_studentcard.py
Normal file
@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.13 on 2018-10-18 23:15
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("counter", "0016_producttype_comment")]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="StudentCard",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"uid",
|
||||
models.CharField(
|
||||
max_length=14,
|
||||
unique=True,
|
||||
validators=[django.core.validators.MinLengthValidator(4)],
|
||||
verbose_name="uid",
|
||||
),
|
||||
),
|
||||
(
|
||||
"customer",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="student_cards",
|
||||
to="counter.Customer",
|
||||
verbose_name="student cards",
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
]
|
@ -27,8 +27,10 @@ from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils import timezone
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.validators import MinLengthValidator
|
||||
from django.forms import ValidationError
|
||||
from django.utils.functional import cached_property
|
||||
from django.core.exceptions import PermissionDenied
|
||||
|
||||
from datetime import timedelta, date
|
||||
import random
|
||||
@ -732,3 +734,42 @@ class Eticket(models.Model):
|
||||
return hmac.new(
|
||||
bytes(self.secret, "utf-8"), bytes(string, "utf-8"), hashlib.sha1
|
||||
).hexdigest()
|
||||
|
||||
|
||||
class StudentCard(models.Model):
|
||||
"""
|
||||
Alternative way to connect a customer into a counter
|
||||
We are using Mifare DESFire EV1 specs since it's used for izly cards
|
||||
https://www.nxp.com/docs/en/application-note/AN10927.pdf
|
||||
UID is 7 byte long that means 14 hexa characters
|
||||
"""
|
||||
|
||||
UID_SIZE = 14
|
||||
|
||||
@staticmethod
|
||||
def is_valid(uid):
|
||||
return (
|
||||
uid.isupper()
|
||||
and len(uid) == StudentCard.UID_SIZE
|
||||
and not StudentCard.objects.filter(uid=uid).exists()
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def can_create(customer, user):
|
||||
return user.pk == customer.user.pk or user.is_board_member or user.is_root
|
||||
|
||||
def can_be_edited_by(self, obj):
|
||||
if isinstance(obj, User):
|
||||
return StudentCard.can_create(self.customer, obj)
|
||||
return False
|
||||
|
||||
uid = models.CharField(
|
||||
_("uid"), max_length=14, unique=True, validators=[MinLengthValidator(4)]
|
||||
)
|
||||
customer = models.ForeignKey(
|
||||
Customer,
|
||||
related_name="student_cards",
|
||||
verbose_name=_("student cards"),
|
||||
null=False,
|
||||
blank=False,
|
||||
)
|
||||
|
@ -30,6 +30,26 @@
|
||||
{{ user_mini_profile(customer.user) }}
|
||||
{{ user_subscription(customer.user) }}
|
||||
<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 %}
|
||||
<input type="input" name="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 customer.student_cards.exists() %}
|
||||
<ul>
|
||||
{% for card in customer.student_cards.all() %}
|
||||
<li>{{ card.uid }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
{% trans %}No card registered{% endtrans %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="bar_ui">
|
||||
<h5>{% trans %}Selling{% endtrans %}</h5>
|
||||
|
240
counter/tests.py
240
counter/tests.py
@ -142,3 +142,243 @@ class BarmanConnectionTest(TestCase):
|
||||
self.assertFalse(
|
||||
'<li><a href="/user/1/">S' Kia</a></li>' in str(response_get.content)
|
||||
)
|
||||
|
||||
|
||||
class StudentCardTest(TestCase):
|
||||
"""
|
||||
Tests for adding and deleting Stundent Cards
|
||||
Test that an user can be found with it's student card
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
call_command("populate")
|
||||
self.krophil = User.objects.get(username="krophil")
|
||||
self.sli = User.objects.get(username="sli")
|
||||
|
||||
self.counter = Counter.objects.filter(id=2).first()
|
||||
|
||||
# Auto login on counter
|
||||
self.client.post(
|
||||
reverse("counter:login", args=[self.counter.id]),
|
||||
{"username": "krophil", "password": "plop"},
|
||||
)
|
||||
|
||||
def test_search_user_with_student_card(self):
|
||||
response = self.client.post(
|
||||
reverse("counter:details", args=[self.counter.id]),
|
||||
{"code": "9A89B82018B0A0"},
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
response.url,
|
||||
reverse(
|
||||
"counter:click",
|
||||
kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
|
||||
),
|
||||
)
|
||||
|
||||
def test_add_student_card_from_counter(self):
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"counter:click",
|
||||
kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
|
||||
),
|
||||
{"student_card_uid": "8B90734A802A8F", "action": "add_student_card"},
|
||||
)
|
||||
self.assertContains(response, text="8B90734A802A8F")
|
||||
|
||||
def test_add_student_card_from_counter_fail(self):
|
||||
# UID too short
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"counter:click",
|
||||
kwargs={"counter_id": self.counter.id, "user_id": self.sli.id},
|
||||
),
|
||||
{"student_card_uid": "8B90734A802A8", "action": "add_student_card"},
|
||||
)
|
||||
self.assertContains(
|
||||
response, text="Ce n'est pas un UID de carte étudiante valide"
|
||||
)
|
||||
|
||||
# UID too long
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"counter:click",
|
||||
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"
|
||||
)
|
||||
|
||||
def test_delete_student_card_with_owner(self):
|
||||
self.client.login(username="sli", password="plop")
|
||||
self.client.post(
|
||||
reverse(
|
||||
"counter:delete_student_card",
|
||||
kwargs={
|
||||
"customer_id": self.sli.customer.pk,
|
||||
"card_id": self.sli.customer.student_cards.first().id,
|
||||
},
|
||||
)
|
||||
)
|
||||
self.assertFalse(self.sli.customer.student_cards.exists())
|
||||
|
||||
def test_delete_student_card_with_board_member(self):
|
||||
self.client.login(username="skia", password="plop")
|
||||
self.client.post(
|
||||
reverse(
|
||||
"counter:delete_student_card",
|
||||
kwargs={
|
||||
"customer_id": self.sli.customer.pk,
|
||||
"card_id": self.sli.customer.student_cards.first().id,
|
||||
},
|
||||
)
|
||||
)
|
||||
self.assertFalse(self.sli.customer.student_cards.exists())
|
||||
|
||||
def test_delete_student_card_with_root(self):
|
||||
self.client.login(username="root", password="plop")
|
||||
self.client.post(
|
||||
reverse(
|
||||
"counter:delete_student_card",
|
||||
kwargs={
|
||||
"customer_id": self.sli.customer.pk,
|
||||
"card_id": self.sli.customer.student_cards.first().id,
|
||||
},
|
||||
)
|
||||
)
|
||||
self.assertFalse(self.sli.customer.student_cards.exists())
|
||||
|
||||
def test_delete_student_card_fail(self):
|
||||
self.client.login(username="krophil", password="plop")
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"counter:delete_student_card",
|
||||
kwargs={
|
||||
"customer_id": self.sli.customer.pk,
|
||||
"card_id": self.sli.customer.student_cards.first().id,
|
||||
},
|
||||
)
|
||||
)
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.assertTrue(self.sli.customer.student_cards.exists())
|
||||
|
||||
def test_add_student_card_from_user_preferences(self):
|
||||
# Test with owner of the card
|
||||
self.client.login(username="sli", password="plop")
|
||||
self.client.post(
|
||||
reverse(
|
||||
"counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
|
||||
),
|
||||
{"uid": "8B90734A802A8F"},
|
||||
)
|
||||
|
||||
response = self.client.get(
|
||||
reverse("core:user_prefs", kwargs={"user_id": self.sli.id})
|
||||
)
|
||||
self.assertContains(response, text="8B90734A802A8F")
|
||||
|
||||
# Test with board member
|
||||
self.client.login(username="skia", password="plop")
|
||||
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 with root
|
||||
self.client.login(username="root", password="plop")
|
||||
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):
|
||||
self.client.login(username="sli", password="plop")
|
||||
# UID too short
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
|
||||
),
|
||||
{"uid": "8B90734A802A8"},
|
||||
)
|
||||
|
||||
self.assertContains(response, text="Cet UID est invalide")
|
||||
|
||||
# UID too long
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
|
||||
),
|
||||
{"uid": "8B90734A802A8FA"},
|
||||
)
|
||||
self.assertContains(response, text="Cet UID est invalide")
|
||||
|
||||
# Test with already existing card
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
|
||||
),
|
||||
{"uid": "9A89B82018B0A0"},
|
||||
)
|
||||
self.assertContains(
|
||||
response, text="Un objet Student card avec ce champ Uid existe déjà."
|
||||
)
|
||||
|
||||
# Test with lowercase
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
|
||||
),
|
||||
{"uid": "8b90734a802a9f"},
|
||||
)
|
||||
self.assertContains(response, text="Cet UID est invalide")
|
||||
|
||||
# Test with unauthorized user
|
||||
self.client.login(username="krophil", password="plop")
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"counter:add_student_card", kwargs={"customer_id": self.sli.customer.pk}
|
||||
),
|
||||
{"uid": "8B90734A802A8F"},
|
||||
)
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
@ -56,6 +56,16 @@ urlpatterns = [
|
||||
EticketPDFView.as_view(),
|
||||
name="eticket_pdf",
|
||||
),
|
||||
url(
|
||||
r"^customer/(?P<customer_id>[0-9]+)/card/add$",
|
||||
StudentCardFormView.as_view(),
|
||||
name="add_student_card",
|
||||
),
|
||||
url(
|
||||
r"^customer/(?P<customer_id>[0-9]+)/card/delete/(?P<card_id>[0-9]+)/$",
|
||||
StudentCardDeleteView.as_view(),
|
||||
name="delete_student_card",
|
||||
),
|
||||
url(r"^admin/(?P<counter_id>[0-9]+)$", CounterEditView.as_view(), name="admin"),
|
||||
url(
|
||||
r"^admin/(?P<counter_id>[0-9]+)/prop$",
|
||||
|
101
counter/views.py
101
counter/views.py
@ -33,6 +33,7 @@ from django.views.generic.edit import (
|
||||
DeleteView,
|
||||
ProcessFormView,
|
||||
FormMixin,
|
||||
FormView,
|
||||
)
|
||||
from django.forms.models import modelform_factory
|
||||
from django.forms import CheckboxSelectMultiple
|
||||
@ -50,13 +51,14 @@ from datetime import date, timedelta, datetime
|
||||
from ajax_select.fields import AutoCompleteSelectField, AutoCompleteSelectMultipleField
|
||||
from ajax_select import make_ajax_field
|
||||
|
||||
from core.views import CanViewMixin, TabedViewMixin
|
||||
from core.views import CanViewMixin, TabedViewMixin, CanEditMixin
|
||||
from core.views.forms import LoginForm, SelectDate, SelectDateTime
|
||||
from core.models import User
|
||||
from subscription.models import Subscription
|
||||
from counter.models import (
|
||||
Counter,
|
||||
Customer,
|
||||
StudentCard,
|
||||
Product,
|
||||
Selling,
|
||||
Refilling,
|
||||
@ -99,6 +101,43 @@ class CounterAdminMixin(View):
|
||||
return super(CounterAdminMixin, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
class StudentCardForm(forms.ModelForm):
|
||||
"""
|
||||
Form for adding student cards
|
||||
Only used for user profile since CounterClick is to complicated
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = StudentCard
|
||||
fields = ["uid"]
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(StudentCardForm, self).clean()
|
||||
uid = cleaned_data.get("uid", None)
|
||||
if not uid or not StudentCard.is_valid(uid):
|
||||
raise forms.ValidationError(_("This UID is invalid"), code="invalid")
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class StudentCardDeleteView(DeleteView, CanEditMixin):
|
||||
"""
|
||||
View used to delete a card from a user
|
||||
"""
|
||||
|
||||
model = StudentCard
|
||||
template_name = "core/delete_confirm.jinja"
|
||||
pk_url_kwarg = "card_id"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.customer = get_object_or_404(Customer, pk=kwargs["customer_id"])
|
||||
return super(StudentCardDeleteView, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
return reverse_lazy(
|
||||
"core:user_prefs", kwargs={"user_id": self.customer.user.pk}
|
||||
)
|
||||
|
||||
|
||||
class GetUserForm(forms.Form):
|
||||
"""
|
||||
The Form class aims at providing a valid user_id field in its cleaned data, in order to pass it to some view,
|
||||
@ -108,7 +147,9 @@ class GetUserForm(forms.Form):
|
||||
some nickname, first name, or last name (TODO)
|
||||
"""
|
||||
|
||||
code = forms.CharField(label="Code", max_length=10, required=False)
|
||||
code = forms.CharField(
|
||||
label="Code", max_length=StudentCard.UID_SIZE, required=False
|
||||
)
|
||||
id = AutoCompleteSelectField(
|
||||
"users", required=False, label=_("Select user"), help_text=None
|
||||
)
|
||||
@ -121,6 +162,11 @@ class GetUserForm(forms.Form):
|
||||
cleaned_data = super(GetUserForm, self).clean()
|
||||
cus = None
|
||||
if cleaned_data["code"] != "":
|
||||
if len(cleaned_data["code"]) == StudentCard.UID_SIZE:
|
||||
card = StudentCard.objects.filter(uid=cleaned_data["code"])
|
||||
if card.exists():
|
||||
cus = card.first().customer
|
||||
if cus is None:
|
||||
cus = Customer.objects.filter(
|
||||
account_id__iexact=cleaned_data["code"]
|
||||
).first()
|
||||
@ -374,6 +420,7 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView):
|
||||
request.session["too_young"] = False
|
||||
request.session["not_allowed"] = False
|
||||
request.session["no_age"] = False
|
||||
request.session["not_valid_student_card_uid"] = False
|
||||
if self.object.type != "BAR":
|
||||
self.operator = request.user
|
||||
elif self.is_barman_price():
|
||||
@ -383,6 +430,8 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView):
|
||||
|
||||
if "add_product" in request.POST["action"]:
|
||||
self.add_product(request)
|
||||
elif "add_student_card" in request.POST["action"]:
|
||||
self.add_student_card(request)
|
||||
elif "del_product" in request.POST["action"]:
|
||||
self.del_product(request)
|
||||
elif "refill" in request.POST["action"]:
|
||||
@ -519,6 +568,27 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView):
|
||||
request.session.modified = True
|
||||
return True
|
||||
|
||||
def add_student_card(self, request):
|
||||
"""
|
||||
Add a new student card on the customer account
|
||||
"""
|
||||
uid = request.POST["student_card_uid"]
|
||||
uid = str(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.keys()
|
||||
and request.session["counter_token"] == self.object.token
|
||||
and len(self.object.get_barmen_list()) > 0
|
||||
):
|
||||
raise PermissionDenied
|
||||
|
||||
StudentCard(customer=self.customer, uid=uid).save()
|
||||
return True
|
||||
|
||||
def del_product(self, request):
|
||||
""" Delete a product from the basket """
|
||||
pid = str(request.POST["product_id"])
|
||||
@ -642,6 +712,7 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView):
|
||||
kwargs["basket_total"] = self.sum_basket(self.request)
|
||||
kwargs["refill_form"] = self.refill_form or RefillForm()
|
||||
kwargs["categories"] = ProductType.objects.all()
|
||||
kwargs["student_card_max_uid_size"] = StudentCard.UID_SIZE
|
||||
return kwargs
|
||||
|
||||
|
||||
@ -1765,3 +1836,29 @@ class CounterRefillingListView(CounterAdminTabsMixin, CounterAdminMixin, ListVie
|
||||
kwargs = super(CounterRefillingListView, self).get_context_data(**kwargs)
|
||||
kwargs["counter"] = self.counter
|
||||
return kwargs
|
||||
|
||||
|
||||
class StudentCardFormView(FormView):
|
||||
"""
|
||||
Add a new student card
|
||||
"""
|
||||
|
||||
form_class = StudentCardForm
|
||||
template_name = "core/create.jinja"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.customer = get_object_or_404(Customer, pk=kwargs["customer_id"])
|
||||
if not StudentCard.can_create(self.customer, request.user):
|
||||
raise PermissionDenied
|
||||
return super(StudentCardFormView, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
def form_valid(self, form):
|
||||
data = form.clean()
|
||||
res = super(FormView, self).form_valid(form)
|
||||
StudentCard(customer=self.customer, uid=data["uid"]).save()
|
||||
return res
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
return reverse_lazy(
|
||||
"core:user_prefs", kwargs={"user_id": self.customer.user.pk}
|
||||
)
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user