mirror of https://gitlab.crans.org/bde/nk20
Compare commits
No commits in common. "24ac3ce45f51cc890678f6c855ef61f2baf76784" and "6c9cf73848d637f4874f4d8dba5890a7308ed278" have entirely different histories.
24ac3ce45f
...
6c9cf73848
|
@ -4,7 +4,7 @@
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from permission.backends import PermissionBackend
|
from permission.backends import PermissionBackend
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
from note_kfet.middlewares import get_current_session
|
from note_kfet.middlewares import get_current_authenticated_user
|
||||||
|
|
||||||
|
|
||||||
class ReadProtectedModelViewSet(viewsets.ModelViewSet):
|
class ReadProtectedModelViewSet(viewsets.ModelViewSet):
|
||||||
|
@ -17,8 +17,7 @@ class ReadProtectedModelViewSet(viewsets.ModelViewSet):
|
||||||
self.model = ContentType.objects.get_for_model(self.serializer_class.Meta.model).model_class()
|
self.model = ContentType.objects.get_for_model(self.serializer_class.Meta.model).model_class()
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
user = self.request.user
|
user = get_current_authenticated_user()
|
||||||
get_current_session().setdefault("permission_mask", 42)
|
|
||||||
return self.model.objects.filter(PermissionBackend.filter_queryset(user, self.model, "view")).distinct()
|
return self.model.objects.filter(PermissionBackend.filter_queryset(user, self.model, "view")).distinct()
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,6 +31,5 @@ class ReadOnlyProtectedModelViewSet(viewsets.ReadOnlyModelViewSet):
|
||||||
self.model = ContentType.objects.get_for_model(self.serializer_class.Meta.model).model_class()
|
self.model = ContentType.objects.get_for_model(self.serializer_class.Meta.model).model_class()
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
user = self.request.user
|
user = get_current_authenticated_user()
|
||||||
get_current_session().setdefault("permission_mask", 42)
|
|
||||||
return self.model.objects.filter(PermissionBackend.filter_queryset(user, self.model, "view")).distinct()
|
return self.model.objects.filter(PermissionBackend.filter_queryset(user, self.model, "view")).distinct()
|
||||||
|
|
|
@ -11,10 +11,10 @@ from django.db import models
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.template import loader
|
from django.template import loader
|
||||||
from django.urls import reverse, reverse_lazy
|
from django.urls import reverse, reverse_lazy
|
||||||
|
from django.utils import timezone
|
||||||
from django.utils.encoding import force_bytes
|
from django.utils.encoding import force_bytes
|
||||||
from django.utils.http import urlsafe_base64_encode
|
from django.utils.http import urlsafe_base64_encode
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from phonenumber_field.modelfields import PhoneNumberField
|
|
||||||
|
|
||||||
from permission.models import Role
|
from permission.models import Role
|
||||||
from registration.tokens import email_validation_token
|
from registration.tokens import email_validation_token
|
||||||
|
@ -34,7 +34,7 @@ class Profile(models.Model):
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
)
|
)
|
||||||
|
|
||||||
phone_number = PhoneNumberField(
|
phone_number = models.CharField(
|
||||||
verbose_name=_('phone number'),
|
verbose_name=_('phone number'),
|
||||||
max_length=50,
|
max_length=50,
|
||||||
blank=True,
|
blank=True,
|
||||||
|
|
|
@ -69,9 +69,7 @@ class UserUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
|
||||||
form.fields['email'].required = True
|
form.fields['email'].required = True
|
||||||
form.fields['email'].help_text = _("This address must be valid.")
|
form.fields['email'].help_text = _("This address must be valid.")
|
||||||
|
|
||||||
context['profile_form'] = self.profile_form(instance=context['user_object'].profile,
|
context['profile_form'] = self.profile_form(instance=context['user_object'].profile)
|
||||||
data=self.request.POST if self.request.POST else None)
|
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
|
@ -88,10 +86,7 @@ class UserUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
|
||||||
data=self.request.POST,
|
data=self.request.POST,
|
||||||
instance=self.object.profile,
|
instance=self.object.profile,
|
||||||
)
|
)
|
||||||
profile_form.full_clean()
|
if form.is_valid() and profile_form.is_valid():
|
||||||
if not profile_form.is_valid():
|
|
||||||
return super().form_invalid(form)
|
|
||||||
|
|
||||||
new_username = form.data['username']
|
new_username = form.data['username']
|
||||||
alias = Alias.objects.filter(name=new_username)
|
alias = Alias.objects.filter(name=new_username)
|
||||||
# Si le nouveau pseudo n'est pas un de nos alias,
|
# Si le nouveau pseudo n'est pas un de nos alias,
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
from django.utils import timezone
|
|
||||||
from rest_framework import serializers
|
|
||||||
from rest_framework.serializers import ListSerializer
|
|
||||||
from rest_polymorphic.serializers import PolymorphicSerializer
|
|
||||||
|
|
||||||
from member.api.serializers import MembershipSerializer
|
from rest_framework import serializers
|
||||||
from member.models import Membership
|
from rest_polymorphic.serializers import PolymorphicSerializer
|
||||||
from note_kfet.middlewares import get_current_authenticated_user
|
from note_kfet.middlewares import get_current_authenticated_user
|
||||||
from permission.backends import PermissionBackend
|
from permission.backends import PermissionBackend
|
||||||
from rest_framework.utils import model_meta
|
|
||||||
|
|
||||||
from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias
|
from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias
|
||||||
from ..models.transactions import TransactionTemplate, Transaction, MembershipTransaction, TemplateCategory, \
|
from ..models.transactions import TransactionTemplate, Transaction, MembershipTransaction, TemplateCategory, \
|
||||||
|
@ -113,8 +108,6 @@ class ConsumerSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
email_confirmed = serializers.SerializerMethodField()
|
email_confirmed = serializers.SerializerMethodField()
|
||||||
|
|
||||||
membership = serializers.SerializerMethodField()
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Alias
|
model = Alias
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
@ -133,17 +126,6 @@ class ConsumerSerializer(serializers.ModelSerializer):
|
||||||
return obj.note.user.profile.email_confirmed
|
return obj.note.user.profile.email_confirmed
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_membership(self, obj):
|
|
||||||
if isinstance(obj.note, NoteUser):
|
|
||||||
memberships = Membership.objects.filter(
|
|
||||||
PermissionBackend.filter_queryset(get_current_authenticated_user(), Membership, "view")).filter(
|
|
||||||
user=obj.note.user,
|
|
||||||
club=2, # Kfet
|
|
||||||
).order_by("-date_start")
|
|
||||||
if memberships.exists():
|
|
||||||
return MembershipSerializer().to_representation(memberships.first())
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
class TemplateCategorySerializer(serializers.ModelSerializer):
|
class TemplateCategorySerializer(serializers.ModelSerializer):
|
||||||
"""
|
"""
|
||||||
|
@ -227,23 +209,5 @@ class TransactionPolymorphicSerializer(PolymorphicSerializer):
|
||||||
except ImportError: # Activity app is not loaded
|
except ImportError: # Activity app is not loaded
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def validate(self, attrs):
|
|
||||||
resource_type = attrs.pop(self.resource_type_field_name)
|
|
||||||
serializer = self._get_serializer_from_resource_type(resource_type)
|
|
||||||
if self.instance:
|
|
||||||
instance = self.instance
|
|
||||||
info = model_meta.get_field_info(instance)
|
|
||||||
for attr, value in attrs.items():
|
|
||||||
if attr in info.relations and info.relations[attr].to_many:
|
|
||||||
field = getattr(instance, attr)
|
|
||||||
field.set(value)
|
|
||||||
else:
|
|
||||||
setattr(instance, attr, value)
|
|
||||||
instance.validate(True)
|
|
||||||
else:
|
|
||||||
serializer.Meta.model(**attrs).validate(True)
|
|
||||||
attrs[self.resource_type_field_name] = resource_type
|
|
||||||
return super().validate(attrs)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Transaction
|
model = Transaction
|
||||||
|
|
|
@ -9,7 +9,7 @@ from rest_framework import viewsets
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from api.viewsets import ReadProtectedModelViewSet, ReadOnlyProtectedModelViewSet
|
from api.viewsets import ReadProtectedModelViewSet, ReadOnlyProtectedModelViewSet
|
||||||
from note_kfet.middlewares import get_current_session
|
from note_kfet.middlewares import get_current_authenticated_user
|
||||||
from permission.backends import PermissionBackend
|
from permission.backends import PermissionBackend
|
||||||
|
|
||||||
from .serializers import NotePolymorphicSerializer, AliasSerializer, ConsumerSerializer,\
|
from .serializers import NotePolymorphicSerializer, AliasSerializer, ConsumerSerializer,\
|
||||||
|
@ -154,7 +154,5 @@ class TransactionViewSet(ReadProtectedModelViewSet):
|
||||||
search_fields = ['$reason', ]
|
search_fields = ['$reason', ]
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
user = self.request.user
|
user = get_current_authenticated_user()
|
||||||
get_current_session().setdefault("permission_mask", 42)
|
return self.model.objects.filter(PermissionBackend.filter_queryset(user, self.model, "view"))
|
||||||
return self.model.objects.filter(PermissionBackend.filter_queryset(user, self.model, "view"))\
|
|
||||||
.order_by("created_at", "id")
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import models, transaction
|
from django.db import models
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
@ -164,49 +164,10 @@ class Transaction(PolymorphicModel):
|
||||||
models.Index(fields=['destination']),
|
models.Index(fields=['destination']),
|
||||||
]
|
]
|
||||||
|
|
||||||
def validate(self, reset=False):
|
|
||||||
previous_source_balance = self.source.balance
|
|
||||||
previous_dest_balance = self.destination.balance
|
|
||||||
|
|
||||||
created = self.pk is None
|
|
||||||
to_transfer = self.amount * self.quantity
|
|
||||||
if not created:
|
|
||||||
# Revert old transaction
|
|
||||||
old_transaction = Transaction.objects.get(pk=self.pk)
|
|
||||||
if old_transaction.valid:
|
|
||||||
self.source.balance += to_transfer
|
|
||||||
self.destination.balance -= to_transfer
|
|
||||||
|
|
||||||
if self.valid:
|
|
||||||
self.source.balance -= to_transfer
|
|
||||||
self.destination.balance += to_transfer
|
|
||||||
|
|
||||||
# When a transaction is declared valid, we ensure that the invalidity reason is null, if it was
|
|
||||||
# previously invalid
|
|
||||||
self.invalidity_reason = None
|
|
||||||
|
|
||||||
source_balance = self.source.balance
|
|
||||||
dest_balance = self.destination.balance
|
|
||||||
|
|
||||||
if reset:
|
|
||||||
self.source.balance = previous_source_balance
|
|
||||||
self.destination.balance = previous_dest_balance
|
|
||||||
|
|
||||||
if source_balance > 2147483647 or source_balance < -2147483648\
|
|
||||||
or dest_balance > 2147483647 or dest_balance < -2147483648:
|
|
||||||
raise ValidationError(_("The note balances must be between - 21 474 836.47 € and 21 474 836.47 €."))
|
|
||||||
|
|
||||||
@transaction.atomic
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
When saving, also transfer money between two notes
|
When saving, also transfer money between two notes
|
||||||
"""
|
"""
|
||||||
with transaction.atomic():
|
|
||||||
if self.pk:
|
|
||||||
self.refresh_from_db()
|
|
||||||
self.source.refresh_from_db()
|
|
||||||
self.destination.refresh_from_db()
|
|
||||||
self.validate(False)
|
|
||||||
|
|
||||||
if not self.source.is_active or not self.destination.is_active:
|
if not self.source.is_active or not self.destination.is_active:
|
||||||
if 'force_insert' not in kwargs or not kwargs['force_insert']:
|
if 'force_insert' not in kwargs or not kwargs['force_insert']:
|
||||||
|
@ -226,22 +187,31 @@ class Transaction(PolymorphicModel):
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
return
|
return
|
||||||
|
|
||||||
self.log("Saving")
|
created = self.pk is None
|
||||||
|
to_transfer = self.amount * self.quantity
|
||||||
|
if not created:
|
||||||
|
# Revert old transaction
|
||||||
|
old_transaction = Transaction.objects.get(pk=self.pk)
|
||||||
|
if old_transaction.valid:
|
||||||
|
self.source.balance += to_transfer
|
||||||
|
self.destination.balance -= to_transfer
|
||||||
|
|
||||||
|
if self.valid:
|
||||||
|
self.source.balance -= to_transfer
|
||||||
|
self.destination.balance += to_transfer
|
||||||
|
|
||||||
|
# When a transaction is declared valid, we ensure that the invalidity reason is null, if it was
|
||||||
|
# previously invalid
|
||||||
|
self.invalidity_reason = None
|
||||||
|
|
||||||
# We save first the transaction, in case of the user has no right to transfer money
|
# We save first the transaction, in case of the user has no right to transfer money
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
self.log("Saved")
|
|
||||||
|
|
||||||
# Save notes
|
# Save notes
|
||||||
self.source._force_save = True
|
self.source._force_save = True
|
||||||
self.source.save()
|
self.source.save()
|
||||||
self.log("Source saved")
|
|
||||||
self.destination._force_save = True
|
self.destination._force_save = True
|
||||||
self.destination.save()
|
self.destination.save()
|
||||||
self.log("Destination saved")
|
|
||||||
|
|
||||||
def log(self, msg):
|
|
||||||
with open("/tmp/log", "a") as f:
|
|
||||||
f.write(msg + "\n")
|
|
||||||
|
|
||||||
def delete(self, **kwargs):
|
def delete(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -10,7 +10,7 @@ from time import sleep
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.mail import mail_admins
|
from django.core.mail import mail_admins
|
||||||
from django.db import models, transaction
|
from django.db import models
|
||||||
from django.db.models import F, Q, Model
|
from django.db.models import F, Q, Model
|
||||||
from django.forms import model_to_dict
|
from django.forms import model_to_dict
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
@ -43,7 +43,14 @@ class InstancedPermission:
|
||||||
|
|
||||||
obj = copy(obj)
|
obj = copy(obj)
|
||||||
obj.pk = 0
|
obj.pk = 0
|
||||||
with transaction.atomic():
|
# Ensure previous models are deleted
|
||||||
|
for ignored in range(1000):
|
||||||
|
if self.model.model_class().objects.filter(pk=0).exists():
|
||||||
|
# If the object exists, that means that one permission is currently checked.
|
||||||
|
# We wait before the other permission, at most 1 second.
|
||||||
|
sleep(0.001)
|
||||||
|
continue
|
||||||
|
break
|
||||||
for o in self.model.model_class().objects.filter(pk=0).all():
|
for o in self.model.model_class().objects.filter(pk=0).all():
|
||||||
o._force_delete = True
|
o._force_delete = True
|
||||||
Model.delete(o)
|
Model.delete(o)
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
import django_tables2 as tables
|
|
||||||
from django.urls import reverse_lazy
|
|
||||||
from django.utils.html import format_html
|
|
||||||
|
|
||||||
from member.models import Membership
|
|
||||||
from note_kfet.middlewares import get_current_authenticated_user
|
|
||||||
from permission.backends import PermissionBackend
|
|
||||||
|
|
||||||
|
|
||||||
class RightsTable(tables.Table):
|
|
||||||
"""
|
|
||||||
List managers of a club.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def render_user(self, value):
|
|
||||||
# If the user has the right, link the displayed user with the page of its detail.
|
|
||||||
s = value.username
|
|
||||||
if PermissionBackend.check_perm(get_current_authenticated_user(), "auth.view_user", value):
|
|
||||||
s = format_html("<a href={url}>{name}</a>",
|
|
||||||
url=reverse_lazy('member:user_detail', kwargs={"pk": value.pk}), name=s)
|
|
||||||
return s
|
|
||||||
|
|
||||||
def render_club(self, value):
|
|
||||||
# If the user has the right, link the displayed user with the page of its detail.
|
|
||||||
s = value.name
|
|
||||||
if PermissionBackend.check_perm(get_current_authenticated_user(), "member.view_club", value):
|
|
||||||
s = format_html("<a href={url}>{name}</a>",
|
|
||||||
url=reverse_lazy('member:club_detail', kwargs={"pk": value.pk}), name=s)
|
|
||||||
|
|
||||||
return s
|
|
||||||
|
|
||||||
def render_roles(self, record):
|
|
||||||
# If the user has the right to manage the roles, display the link to manage them
|
|
||||||
roles = record.roles.all()
|
|
||||||
s = ", ".join(str(role) for role in roles)
|
|
||||||
if PermissionBackend.check_perm(get_current_authenticated_user(), "member.change_membership_roles", record):
|
|
||||||
s = format_html("<a href='" + str(reverse_lazy("member:club_manage_roles", kwargs={"pk": record.pk}))
|
|
||||||
+ "'>" + s + "</a>")
|
|
||||||
return s
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
attrs = {
|
|
||||||
'class': 'table table-condensed table-striped table-hover',
|
|
||||||
'style': 'table-layout: fixed;'
|
|
||||||
}
|
|
||||||
template_name = 'django_tables2/bootstrap4.html'
|
|
||||||
fields = ('user.last_name', 'user.first_name', 'user', 'club', 'roles', )
|
|
||||||
model = Membership
|
|
|
@ -2,16 +2,13 @@
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
|
||||||
from django.db.models import Q
|
|
||||||
from django.forms import HiddenInput
|
from django.forms import HiddenInput
|
||||||
from django.utils import timezone
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.generic import UpdateView, TemplateView
|
from django.views.generic import UpdateView, TemplateView
|
||||||
from member.models import Membership
|
from member.models import Membership
|
||||||
|
|
||||||
from .backends import PermissionBackend
|
from .backends import PermissionBackend
|
||||||
from .models import Role
|
from .models import Role
|
||||||
from .tables import RightsTable
|
|
||||||
|
|
||||||
|
|
||||||
class ProtectQuerysetMixin:
|
class ProtectQuerysetMixin:
|
||||||
|
@ -62,16 +59,4 @@ class RightsView(TemplateView):
|
||||||
for role in roles:
|
for role in roles:
|
||||||
role.clubs = [membership.club for membership in active_memberships if role in membership.roles.all()]
|
role.clubs = [membership.club for membership in active_memberships if role in membership.roles.all()]
|
||||||
|
|
||||||
if self.request.user.is_authenticated:
|
|
||||||
special_memberships = Membership.objects.filter(
|
|
||||||
date_start__lte=timezone.now().date(),
|
|
||||||
date_end__gte=timezone.now().date(),
|
|
||||||
).filter(roles__in=Role.objects.filter(~(Q(name="Adhérent BDE")
|
|
||||||
| Q(name="Adhérent Kfet")
|
|
||||||
| Q(name="Membre de club")
|
|
||||||
| Q(name="Adhérent WEI")
|
|
||||||
| Q(name="1A")))).order_by("club", "user__last_name")\
|
|
||||||
.distinct().all()
|
|
||||||
context["special_memberships_table"] = RightsTable(special_memberships)
|
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
|
@ -39,7 +39,7 @@ class UserCreateView(CreateView):
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context["profile_form"] = self.second_form(self.request.POST if self.request.POST else None)
|
context["profile_form"] = self.second_form()
|
||||||
del context["profile_form"].fields["section"]
|
del context["profile_form"].fields["section"]
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
from crispy_forms.helper import FormHelper
|
from crispy_forms.helper import FormHelper
|
||||||
from crispy_forms.layout import Submit
|
from crispy_forms.layout import Submit
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils import timezone
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from note_kfet.inputs import DatePickerInput, AmountInput
|
from note_kfet.inputs import DatePickerInput, AmountInput
|
||||||
|
|
||||||
|
@ -18,13 +19,12 @@ class InvoiceForm(forms.ModelForm):
|
||||||
|
|
||||||
# Django forms don't support date fields. We have to add it manually
|
# Django forms don't support date fields. We have to add it manually
|
||||||
date = forms.DateField(
|
date = forms.DateField(
|
||||||
initial=timezone.now,
|
initial=datetime.date.today,
|
||||||
widget=DatePickerInput(),
|
widget=DatePickerInput()
|
||||||
)
|
)
|
||||||
|
|
||||||
def clean_date(self):
|
def clean_date(self):
|
||||||
self.instance.date = self.data.get("date")
|
self.instance.date = self.data.get("date")
|
||||||
return self.instance.date
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Invoice
|
model = Invoice
|
||||||
|
@ -36,11 +36,7 @@ class ProductForm(forms.ModelForm):
|
||||||
model = Product
|
model = Product
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
widgets = {
|
widgets = {
|
||||||
"amount": AmountInput(
|
"amount": AmountInput()
|
||||||
attrs={
|
|
||||||
"negative": True,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,12 +115,6 @@ class LinkTransactionToRemittanceForm(forms.ModelForm):
|
||||||
"""
|
"""
|
||||||
Attach a special transaction to a remittance.
|
Attach a special transaction to a remittance.
|
||||||
"""
|
"""
|
||||||
remittance = forms.ModelChoiceField(
|
|
||||||
queryset=Remittance.objects.none(),
|
|
||||||
label=_("Remittance"),
|
|
||||||
empty_label=_("No attached remittance"),
|
|
||||||
required=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Since we use a proxy model for special transactions, we add manually the fields related to the transaction
|
# Since we use a proxy model for special transactions, we add manually the fields related to the transaction
|
||||||
last_name = forms.CharField(label=_("Last name"))
|
last_name = forms.CharField(label=_("Last name"))
|
||||||
|
@ -133,7 +123,7 @@ class LinkTransactionToRemittanceForm(forms.ModelForm):
|
||||||
|
|
||||||
bank = forms.Field(label=_("Bank"))
|
bank = forms.Field(label=_("Bank"))
|
||||||
|
|
||||||
amount = forms.IntegerField(label=_("Amount"), min_value=0, widget=AmountInput(), disabled=True, required=False)
|
amount = forms.IntegerField(label=_("Amount"), min_value=0)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
@ -143,19 +133,33 @@ class LinkTransactionToRemittanceForm(forms.ModelForm):
|
||||||
|
|
||||||
self.fields["remittance"].queryset = Remittance.objects.filter(closed=False)
|
self.fields["remittance"].queryset = Remittance.objects.filter(closed=False)
|
||||||
|
|
||||||
def clean(self):
|
def clean_last_name(self):
|
||||||
cleaned_data = super().clean()
|
"""
|
||||||
self.instance.transaction.last_name = cleaned_data["last_name"]
|
Replace the first name in the information of the transaction.
|
||||||
self.instance.transaction.first_name = cleaned_data["first_name"]
|
"""
|
||||||
self.instance.transaction.bank = cleaned_data["bank"]
|
self.instance.transaction.last_name = self.data.get("last_name")
|
||||||
return cleaned_data
|
self.instance.transaction.clean()
|
||||||
|
|
||||||
def save(self, commit=True):
|
def clean_first_name(self):
|
||||||
"""
|
"""
|
||||||
Save the transaction and the remittance.
|
Replace the last name in the information of the transaction.
|
||||||
"""
|
"""
|
||||||
self.instance.transaction.save()
|
self.instance.transaction.first_name = self.data.get("first_name")
|
||||||
return super().save(commit)
|
self.instance.transaction.clean()
|
||||||
|
|
||||||
|
def clean_bank(self):
|
||||||
|
"""
|
||||||
|
Replace the bank in the information of the transaction.
|
||||||
|
"""
|
||||||
|
self.instance.transaction.bank = self.data.get("bank")
|
||||||
|
self.instance.transaction.clean()
|
||||||
|
|
||||||
|
def clean_amount(self):
|
||||||
|
"""
|
||||||
|
Replace the amount of the transaction.
|
||||||
|
"""
|
||||||
|
self.instance.transaction.amount = self.data.get("amount")
|
||||||
|
self.instance.transaction.clean()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SpecialTransactionProxy
|
model = SpecialTransactionProxy
|
||||||
|
|
|
@ -82,7 +82,7 @@ class Product(models.Model):
|
||||||
verbose_name=_("Designation"),
|
verbose_name=_("Designation"),
|
||||||
)
|
)
|
||||||
|
|
||||||
quantity = models.IntegerField(
|
quantity = models.PositiveIntegerField(
|
||||||
verbose_name=_("Quantity")
|
verbose_name=_("Quantity")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,6 @@ class RemittanceTable(tables.Table):
|
||||||
model = Remittance
|
model = Remittance
|
||||||
template_name = 'django_tables2/bootstrap4.html'
|
template_name = 'django_tables2/bootstrap4.html'
|
||||||
fields = ('id', 'date', 'remittance_type', 'comment', 'count', 'amount', 'view',)
|
fields = ('id', 'date', 'remittance_type', 'comment', 'count', 'amount', 'view',)
|
||||||
order_by = ('-date',)
|
|
||||||
|
|
||||||
|
|
||||||
class SpecialTransactionTable(tables.Table):
|
class SpecialTransactionTable(tables.Table):
|
||||||
|
@ -101,8 +100,7 @@ class SpecialTransactionTable(tables.Table):
|
||||||
}
|
}
|
||||||
model = SpecialTransaction
|
model = SpecialTransaction
|
||||||
template_name = 'django_tables2/bootstrap4.html'
|
template_name = 'django_tables2/bootstrap4.html'
|
||||||
fields = ('created_at', 'source', 'destination', 'last_name', 'first_name', 'bank', 'amount', 'reason',)
|
fields = ('id', 'source', 'destination', 'last_name', 'first_name', 'bank', 'amount', 'reason',)
|
||||||
order_by = ('-created_at',)
|
|
||||||
|
|
||||||
|
|
||||||
class SogeCreditTable(tables.Table):
|
class SogeCreditTable(tables.Table):
|
||||||
|
|
|
@ -238,7 +238,7 @@ class RemittanceListView(LoginRequiredMixin, TemplateView):
|
||||||
|
|
||||||
closed_remittances = RemittanceTable(
|
closed_remittances = RemittanceTable(
|
||||||
data=Remittance.objects.filter(closed=True).filter(
|
data=Remittance.objects.filter(closed=True).filter(
|
||||||
PermissionBackend.filter_queryset(self.request.user, Remittance, "view")).all(),
|
PermissionBackend.filter_queryset(self.request.user, Remittance, "view")).reverse().all(),
|
||||||
prefix="closed-remittances-",
|
prefix="closed-remittances-",
|
||||||
)
|
)
|
||||||
closed_remittances.paginate(page=self.request.GET.get("closed-remittances-page", 1), per_page=10)
|
closed_remittances.paginate(page=self.request.GET.get("closed-remittances-page", 1), per_page=10)
|
||||||
|
@ -281,6 +281,8 @@ class RemittanceUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView)
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
context["table"] = RemittanceTable(data=Remittance.objects.filter(
|
||||||
|
PermissionBackend.filter_queryset(self.request.user, Remittance, "view")).all())
|
||||||
data = SpecialTransaction.objects.filter(specialtransactionproxy__remittance=self.object).filter(
|
data = SpecialTransaction.objects.filter(specialtransactionproxy__remittance=self.object).filter(
|
||||||
PermissionBackend.filter_queryset(self.request.user, Remittance, "view")).all()
|
PermissionBackend.filter_queryset(self.request.user, Remittance, "view")).all()
|
||||||
context["special_transactions"] = SpecialTransactionTable(
|
context["special_transactions"] = SpecialTransactionTable(
|
||||||
|
|
|
@ -8,8 +8,6 @@ from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from phonenumber_field.modelfields import PhoneNumberField
|
|
||||||
|
|
||||||
from member.models import Club, Membership
|
from member.models import Club, Membership
|
||||||
from note.models import MembershipTransaction
|
from note.models import MembershipTransaction
|
||||||
from permission.models import Role
|
from permission.models import Role
|
||||||
|
@ -225,7 +223,7 @@ class WEIRegistration(models.Model):
|
||||||
verbose_name=_("emergency contact name"),
|
verbose_name=_("emergency contact name"),
|
||||||
)
|
)
|
||||||
|
|
||||||
emergency_contact_phone = PhoneNumberField(
|
emergency_contact_phone = models.CharField(
|
||||||
max_length=32,
|
max_length=32,
|
||||||
verbose_name=_("emergency contact phone"),
|
verbose_name=_("emergency contact phone"),
|
||||||
)
|
)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -37,7 +37,6 @@ INSTALLED_APPS = [
|
||||||
|
|
||||||
# External apps
|
# External apps
|
||||||
'mailer',
|
'mailer',
|
||||||
'phonenumber_field',
|
|
||||||
'polymorphic',
|
'polymorphic',
|
||||||
'crispy_forms',
|
'crispy_forms',
|
||||||
'django_tables2',
|
'django_tables2',
|
||||||
|
@ -196,7 +195,3 @@ MEDIA_URL = '/media/'
|
||||||
# Profile Picture Settings
|
# Profile Picture Settings
|
||||||
PIC_WIDTH = 200
|
PIC_WIDTH = 200
|
||||||
PIC_RATIO = 1
|
PIC_RATIO = 1
|
||||||
|
|
||||||
|
|
||||||
PHONENUMBER_DB_FORMAT = 'NATIONAL'
|
|
||||||
PHONENUMBER_DEFAULT_REGION = 'FR'
|
|
||||||
|
|
|
@ -7,13 +7,11 @@ django-crispy-forms==1.7.2
|
||||||
django-extensions==2.1.9
|
django-extensions==2.1.9
|
||||||
django-filter==2.2.0
|
django-filter==2.2.0
|
||||||
django-mailer==2.0.1
|
django-mailer==2.0.1
|
||||||
django-phonenumber-field==4.0.0
|
|
||||||
django-polymorphic==2.0.3
|
django-polymorphic==2.0.3
|
||||||
django-tables2==2.1.0
|
django-tables2==2.1.0
|
||||||
docutils==0.14
|
docutils==0.14
|
||||||
idna==2.8
|
idna==2.8
|
||||||
oauthlib==3.1.0
|
oauthlib==3.1.0
|
||||||
phonenumbers==8.12.7
|
|
||||||
Pillow==7.1.2
|
Pillow==7.1.2
|
||||||
python3-openid==3.1.0
|
python3-openid==3.1.0
|
||||||
pytz==2019.1
|
pytz==2019.1
|
||||||
|
|
|
@ -105,10 +105,8 @@ function displayStyle(note) {
|
||||||
css += " text-danger";
|
css += " text-danger";
|
||||||
else if (balance < 0)
|
else if (balance < 0)
|
||||||
css += " text-warning";
|
css += " text-warning";
|
||||||
else if (!note.email_confirmed)
|
if (!note.email_confirmed)
|
||||||
css += " text-white bg-primary";
|
css += " text-white bg-primary";
|
||||||
else if (note.membership && note.membership.date_end < new Date().toISOString())
|
|
||||||
css += "text-white bg-info";
|
|
||||||
return css;
|
return css;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,9 +131,13 @@ function displayNote(note, alias, user_note_field = null, profile_pic_field = nu
|
||||||
$("#" + user_note_field).text(alias + (note.balance == null ? "" : (" :\n" + pretty_money(note.balance))));
|
$("#" + user_note_field).text(alias + (note.balance == null ? "" : (" :\n" + pretty_money(note.balance))));
|
||||||
if (profile_pic_field != null) {
|
if (profile_pic_field != null) {
|
||||||
$("#" + profile_pic_field).attr('src', img);
|
$("#" + profile_pic_field).attr('src', img);
|
||||||
$("#" + profile_pic_field + "_link").attr('href', note.resourcetype === "NoteUser" ?
|
$("#" + profile_pic_field).click(function () {
|
||||||
"/accounts/user/" + note.user : note.resourcetype === "NoteClub" ?
|
if (note.resourcetype === "NoteUser") {
|
||||||
"/accounts/club/" + note.club : "#");
|
document.location.href = "/accounts/user/" + note.user;
|
||||||
|
} else if (note.resourcetype === "NoteClub") {
|
||||||
|
document.location.href = "/accounts/club/" + note.club;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,7 +267,6 @@ function autoCompleteNote(field_id, note_list_id, notes, notes_display, alias_pr
|
||||||
consumers.results.forEach(function (consumer) {
|
consumers.results.forEach(function (consumer) {
|
||||||
let note = consumer.note;
|
let note = consumer.note;
|
||||||
note.email_confirmed = consumer.email_confirmed;
|
note.email_confirmed = consumer.email_confirmed;
|
||||||
note.membership = consumer.membership;
|
|
||||||
let extra_css = displayStyle(note);
|
let extra_css = displayStyle(note);
|
||||||
aliases_matched_html += li(alias_prefix + '_' + consumer.id,
|
aliases_matched_html += li(alias_prefix + '_' + consumer.id,
|
||||||
consumer.name,
|
consumer.name,
|
||||||
|
@ -370,12 +371,8 @@ function de_validate(id, validated) {
|
||||||
refreshHistory();
|
refreshHistory();
|
||||||
},
|
},
|
||||||
error: function (err) {
|
error: function (err) {
|
||||||
let errObj = JSON.parse(err.responseText);
|
|
||||||
let error = errObj["detail"] ? errObj["detail"] : errObj["non_field_errors"];
|
|
||||||
if (!error)
|
|
||||||
error = err.responseText;
|
|
||||||
addMsg("Une erreur est survenue lors de la validation/dévalidation " +
|
addMsg("Une erreur est survenue lors de la validation/dévalidation " +
|
||||||
"de cette transaction : " + error, "danger");
|
"de cette transaction : " + JSON.parse(err.responseText)["detail"], "danger", 10000);
|
||||||
|
|
||||||
refreshBalance();
|
refreshBalance();
|
||||||
// error if this method doesn't exist. Please define it.
|
// error if this method doesn't exist. Please define it.
|
||||||
|
|
|
@ -145,7 +145,6 @@ function reset() {
|
||||||
$("#consos_list").html("");
|
$("#consos_list").html("");
|
||||||
$("#user_note").text("");
|
$("#user_note").text("");
|
||||||
$("#profile_pic").attr("src", "/media/pic/default.png");
|
$("#profile_pic").attr("src", "/media/pic/default.png");
|
||||||
$("#profile_pic_link").attr("href", "#");
|
|
||||||
refreshHistory();
|
refreshHistory();
|
||||||
refreshBalance();
|
refreshBalance();
|
||||||
}
|
}
|
||||||
|
@ -213,14 +212,11 @@ function consume(source, source_alias, dest, quantity, amount, reason, type, cat
|
||||||
if (newBalance <= -5000)
|
if (newBalance <= -5000)
|
||||||
addMsg("Attention, La transaction depuis la note " + source_alias + " a été réalisée avec " +
|
addMsg("Attention, La transaction depuis la note " + source_alias + " a été réalisée avec " +
|
||||||
"succès, mais la note émettrice " + source_alias + " est en négatif sévère.",
|
"succès, mais la note émettrice " + source_alias + " est en négatif sévère.",
|
||||||
"danger", 30000);
|
"danger", 10000);
|
||||||
else if (newBalance < 0)
|
else if (newBalance < 0)
|
||||||
addMsg("Attention, La transaction depuis la note " + source_alias + " a été réalisée avec " +
|
addMsg("Attention, La transaction depuis la note " + source_alias + " a été réalisée avec " +
|
||||||
"succès, mais la note émettrice " + source_alias + " est en négatif.",
|
"succès, mais la note émettrice " + source_alias + " est en négatif.",
|
||||||
"warning", 30000);
|
"warning", 10000);
|
||||||
if (source.note.membership && source.note.membership.date_end > new Date().toISOString())
|
|
||||||
addMsg("Attention : la note émettrice " + source.name + " n'est plus adhérente.",
|
|
||||||
"danger", 30000);
|
|
||||||
}
|
}
|
||||||
reset();
|
reset();
|
||||||
}).fail(function (e) {
|
}).fail(function (e) {
|
||||||
|
@ -244,7 +240,7 @@ function consume(source, source_alias, dest, quantity, amount, reason, type, cat
|
||||||
addMsg("La transaction n'a pas pu être validée pour cause de solde insuffisant.", "danger", 10000);
|
addMsg("La transaction n'a pas pu être validée pour cause de solde insuffisant.", "danger", 10000);
|
||||||
}).fail(function () {
|
}).fail(function () {
|
||||||
reset();
|
reset();
|
||||||
errMsg(e.responseJSON);
|
errMsg(e.responseJSON, 10000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,6 @@ function reset(refresh=true) {
|
||||||
$("#bank").val("");
|
$("#bank").val("");
|
||||||
$("#user_note").val("");
|
$("#user_note").val("");
|
||||||
$("#profile_pic").attr("src", "/media/pic/default.png");
|
$("#profile_pic").attr("src", "/media/pic/default.png");
|
||||||
$("#profile_pic_link").attr("href", "#");
|
|
||||||
if (refresh) {
|
if (refresh) {
|
||||||
refreshBalance();
|
refreshBalance();
|
||||||
refreshHistory();
|
refreshHistory();
|
||||||
|
@ -214,13 +213,6 @@ $("#btn_transfer").click(function() {
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let amount = Math.floor(100 * amount_field.val());
|
|
||||||
if (amount > 2147483647) {
|
|
||||||
amount_field.addClass('is-invalid');
|
|
||||||
$("#amount-required").html("<strong>Le montant ne doit pas excéder 21474836.47 €.</strong>");
|
|
||||||
error = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!reason_field.val()) {
|
if (!reason_field.val()) {
|
||||||
reason_field.addClass('is-invalid');
|
reason_field.addClass('is-invalid');
|
||||||
$("#reason-required").html("<strong>Ce champ est requis.</strong>");
|
$("#reason-required").html("<strong>Ce champ est requis.</strong>");
|
||||||
|
@ -240,6 +232,7 @@ $("#btn_transfer").click(function() {
|
||||||
if (error)
|
if (error)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
let amount = 100 * amount_field.val();
|
||||||
let reason = reason_field.val();
|
let reason = reason_field.val();
|
||||||
|
|
||||||
if ($("#type_transfer").is(':checked')) {
|
if ($("#type_transfer").is(':checked')) {
|
||||||
|
@ -260,13 +253,6 @@ $("#btn_transfer").click(function() {
|
||||||
"destination": dest.note.id,
|
"destination": dest.note.id,
|
||||||
"destination_alias": dest.name
|
"destination_alias": dest.name
|
||||||
}).done(function () {
|
}).done(function () {
|
||||||
if (source.note.membership && source.note.membership.date_end > new Date().toISOString())
|
|
||||||
addMsg("Attention : la note émettrice " + source.name + " n'est plus adhérente.",
|
|
||||||
"danger", 30000);
|
|
||||||
if (dest.note.membership && dest.note.membership.date_end > new Date().toISOString())
|
|
||||||
addMsg("Attention : la note destination " + dest.name + " n'est plus adhérente.",
|
|
||||||
"danger", 30000);
|
|
||||||
|
|
||||||
if (!isNaN(source.note.balance)) {
|
if (!isNaN(source.note.balance)) {
|
||||||
let newBalance = source.note.balance - source.quantity * dest.quantity * amount;
|
let newBalance = source.note.balance - source.quantity * dest.quantity * amount;
|
||||||
if (newBalance <= -5000) {
|
if (newBalance <= -5000) {
|
||||||
|
@ -291,15 +277,7 @@ $("#btn_transfer").click(function() {
|
||||||
+ " vers la note " + dest.name + " a été fait avec succès !", "success", 10000);
|
+ " vers la note " + dest.name + " a été fait avec succès !", "success", 10000);
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
}).fail(function (err) { // do it again but valid = false
|
}).fail(function () { // do it again but valid = false
|
||||||
let errObj = JSON.parse(err.responseText);
|
|
||||||
if (errObj["non_field_errors"]) {
|
|
||||||
addMsg("Le transfert de "
|
|
||||||
+ pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name
|
|
||||||
+ " vers la note " + dest.name + " a échoué : " + errObj["non_field_errors"], "danger");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$.post("/api/note/transaction/transaction/",
|
$.post("/api/note/transaction/transaction/",
|
||||||
{
|
{
|
||||||
"csrfmiddlewaretoken": CSRF_TOKEN,
|
"csrfmiddlewaretoken": CSRF_TOKEN,
|
||||||
|
@ -320,13 +298,9 @@ $("#btn_transfer").click(function() {
|
||||||
+ " vers la note " + dest.name + " a échoué : Solde insuffisant", "danger", 10000);
|
+ " vers la note " + dest.name + " a échoué : Solde insuffisant", "danger", 10000);
|
||||||
reset();
|
reset();
|
||||||
}).fail(function (err) {
|
}).fail(function (err) {
|
||||||
let errObj = JSON.parse(err.responseText);
|
|
||||||
let error = errObj["detail"] ? errObj["detail"] : errObj["non_field_errors"]
|
|
||||||
if (!error)
|
|
||||||
error = err.responseText;
|
|
||||||
addMsg("Le transfert de "
|
addMsg("Le transfert de "
|
||||||
+ pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name
|
+ pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name
|
||||||
+ " vers la note " + dest.name + " a échoué : " + error, "danger");
|
+ " vers la note " + dest.name + " a échoué : " + err.responseText, "danger");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -334,22 +308,19 @@ $("#btn_transfer").click(function() {
|
||||||
} else if ($("#type_credit").is(':checked') || $("#type_debit").is(':checked')) {
|
} else if ($("#type_credit").is(':checked') || $("#type_debit").is(':checked')) {
|
||||||
let special_note = $("#credit_type").val();
|
let special_note = $("#credit_type").val();
|
||||||
let user_note;
|
let user_note;
|
||||||
let alias;
|
|
||||||
let given_reason = reason;
|
let given_reason = reason;
|
||||||
let source_id, dest_id;
|
let source_id, dest_id;
|
||||||
if ($("#type_credit").is(':checked')) {
|
if ($("#type_credit").is(':checked')) {
|
||||||
user_note = dests_notes_display[0].note;
|
user_note = dests_notes_display[0].note.id;
|
||||||
alias = dests_notes_display[0].name;
|
|
||||||
source_id = special_note;
|
source_id = special_note;
|
||||||
dest_id = user_note.id;
|
dest_id = user_note;
|
||||||
reason = "Crédit " + $("#credit_type option:selected").text().toLowerCase();
|
reason = "Crédit " + $("#credit_type option:selected").text().toLowerCase();
|
||||||
if (given_reason.length > 0)
|
if (given_reason.length > 0)
|
||||||
reason += " (" + given_reason + ")";
|
reason += " (" + given_reason + ")";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
user_note = sources_notes_display[0].note;
|
user_note = sources_notes_display[0].note.id;
|
||||||
alias = sources_notes_display[0].name;
|
source_id = user_note;
|
||||||
source_id = user_note.id;
|
|
||||||
dest_id = special_note;
|
dest_id = special_note;
|
||||||
reason = "Retrait " + $("#credit_type option:selected").text().toLowerCase();
|
reason = "Retrait " + $("#credit_type option:selected").text().toLowerCase();
|
||||||
if (given_reason.length > 0)
|
if (given_reason.length > 0)
|
||||||
|
@ -365,23 +336,18 @@ $("#btn_transfer").click(function() {
|
||||||
"polymorphic_ctype": SPECIAL_TRANSFER_POLYMORPHIC_CTYPE,
|
"polymorphic_ctype": SPECIAL_TRANSFER_POLYMORPHIC_CTYPE,
|
||||||
"resourcetype": "SpecialTransaction",
|
"resourcetype": "SpecialTransaction",
|
||||||
"source": source_id,
|
"source": source_id,
|
||||||
"source_alias": sources_notes_display.length ? alias : null,
|
"source_alias": sources_notes_display.length ? sources_notes_display[0].name : null,
|
||||||
"destination": dest_id,
|
"destination": dest_id,
|
||||||
"destination_alias": dests_notes_display.length ? alias : null,
|
"destination_alias": dests_notes_display.length ? dests_notes_display[0].name : null,
|
||||||
"last_name": $("#last_name").val(),
|
"last_name": $("#last_name").val(),
|
||||||
"first_name": $("#first_name").val(),
|
"first_name": $("#first_name").val(),
|
||||||
"bank": $("#bank").val()
|
"bank": $("#bank").val()
|
||||||
}).done(function () {
|
}).done(function () {
|
||||||
addMsg("Le crédit/retrait a bien été effectué !", "success", 10000);
|
addMsg("Le crédit/retrait a bien été effectué !", "success", 10000);
|
||||||
if (user_note.membership && user_note.membership.date_end > new Date().toISOString())
|
|
||||||
addMsg("Attention : la note " + alias + " n'est plus adhérente.", "danger", 10000);
|
|
||||||
reset();
|
reset();
|
||||||
}).fail(function (err) {
|
}).fail(function (err) {
|
||||||
let errObj = JSON.parse(err.responseText);
|
addMsg("Le crédit/retrait a échoué : " + JSON.parse(err.responseText)["detail"],
|
||||||
let error = errObj["detail"] ? errObj["detail"] : errObj["non_field_errors"]
|
"danger", 10000);
|
||||||
if (!error)
|
|
||||||
error = err.responseText;
|
|
||||||
addMsg("Le crédit/retrait a échoué : " + error, "danger", 10000);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input class="form-control mx-auto d-block" type="number" {% if not widget.attrs.negative %}min="0"{% endif %} step="0.01"
|
<input class="form-control mx-auto d-block" type="number" min="0" step="0.01"
|
||||||
{% if widget.value != None and widget.value != "" %}value="{{ widget.value }}"{% endif %}
|
{% if widget.value != None and widget.value != "" %}value="{{ widget.value }}"{% endif %}
|
||||||
name="{{ widget.name }}"
|
name="{{ widget.name }}"
|
||||||
{% for name, value in widget.attrs.items %}
|
{% for name, value in widget.attrs.items %}
|
||||||
|
|
|
@ -12,10 +12,8 @@
|
||||||
{# User details column #}
|
{# User details column #}
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="card border-success shadow mb-4 text-center">
|
<div class="card border-success shadow mb-4 text-center">
|
||||||
<a id="profile_pic_link" href="#">
|
|
||||||
<img src="/media/pic/default.png"
|
<img src="/media/pic/default.png"
|
||||||
id="profile_pic" alt="" class="card-img-top">
|
id="profile_pic" alt="" class="card-img-top">
|
||||||
</a>
|
|
||||||
<div class="card-body text-center">
|
<div class="card-body text-center">
|
||||||
<span id="user_note"></span>
|
<span id="user_note"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -36,8 +36,8 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3" id="note_infos_div">
|
<div class="col-md-3" id="note_infos_div">
|
||||||
<div class="card border-success shadow mb-4">
|
<div class="card border-success shadow mb-4">
|
||||||
<a id="profile_pic_link" href="#"><img src="/media/pic/default.png"
|
<img src="/media/pic/default.png"
|
||||||
id="profile_pic" alt="" class="img-fluid rounded mx-auto d-block"></a>
|
id="profile_pic" alt="" class="img-fluid rounded mx-auto d-block">
|
||||||
<div class="card-body text-center">
|
<div class="card-body text-center">
|
||||||
<span id="user_note"></span>
|
<span id="user_note"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,17 +1,8 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load render_table from django_tables2 %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if user.is_authenticated %}
|
|
||||||
<h2>{% trans "Users that have surnormal rights" %}</h2>
|
|
||||||
{% render_table special_memberships_table %}
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<h2>{% trans "Roles description" %}</h2>
|
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<label for="owned_only" class="form-check-label">
|
<label for="owned_only" class="form-check-label">
|
||||||
|
@ -20,7 +11,6 @@
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
{% regroup active_memberships by roles as memberships_per_role %}
|
{% regroup active_memberships by roles as memberships_per_role %}
|
||||||
{% for role in roles %}
|
{% for role in roles %}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>{% trans "Account activation" %}</h2>
|
<h2>{% trans "Account activation" %}</h2>
|
||||||
|
|
Loading…
Reference in New Issue