mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-11-04 01:12:08 +01:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master' into activity
This commit is contained in:
		@@ -4,6 +4,7 @@
 | 
			
		||||
import datetime
 | 
			
		||||
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.core.exceptions import ValidationError
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.urls import reverse, reverse_lazy
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
@@ -67,6 +68,13 @@ class Club(models.Model):
 | 
			
		||||
    email = models.EmailField(
 | 
			
		||||
        verbose_name=_('email'),
 | 
			
		||||
    )
 | 
			
		||||
    parent_club = models.ForeignKey(
 | 
			
		||||
        'self',
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True,
 | 
			
		||||
        on_delete=models.PROTECT,
 | 
			
		||||
        verbose_name=_('parent club'),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # Memberships
 | 
			
		||||
    membership_fee = models.PositiveIntegerField(
 | 
			
		||||
@@ -158,6 +166,12 @@ class Membership(models.Model):
 | 
			
		||||
        else:
 | 
			
		||||
            return self.date_start.toordinal() <= datetime.datetime.now().toordinal()
 | 
			
		||||
 | 
			
		||||
    def save(self, *args, **kwargs):
 | 
			
		||||
        if self.club.parent_club is not None:
 | 
			
		||||
            if not Membership.objects.filter(user=self.user, club=self.club.parent_club):
 | 
			
		||||
                raise ValidationError(_('User is not a member of the parent club'))
 | 
			
		||||
        super().save(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        verbose_name = _('membership')
 | 
			
		||||
        verbose_name_plural = _('memberships')
 | 
			
		||||
 
 | 
			
		||||
@@ -14,12 +14,12 @@ urlpatterns = [
 | 
			
		||||
    path('club/create/', views.ClubCreateView.as_view(), name="club_create"),
 | 
			
		||||
    path('club/<int:pk>/update', views.ClubUpdateView.as_view(), name="club_update"),
 | 
			
		||||
    path('club/<int:pk>/update_pic', views.ClubPictureUpdateView.as_view(), name="club_update_pic"),
 | 
			
		||||
    path('club/<int:pk>/aliases', views.ClubAliasView.as_view(), name="club_alias"),
 | 
			
		||||
    path('user/', views.UserListView.as_view(), name="user_list"),
 | 
			
		||||
    path('user/<int:pk>', views.UserDetailView.as_view(), name="user_detail"),
 | 
			
		||||
    path('user/<int:pk>/update', views.UserUpdateView.as_view(), name="user_update_profile"),
 | 
			
		||||
    path('user/<int:pk>/update_pic', views.ProfilePictureUpdateView.as_view(), name="user_update_pic"),
 | 
			
		||||
    path('user/<int:pk>/aliases', views.AliasView.as_view(), name="user_alias"),
 | 
			
		||||
    path('user/aliases/delete/<int:pk>', views.DeleteAliasView.as_view(), name="user_alias_delete"),
 | 
			
		||||
    path('user/<int:pk>/aliases', views.ProfileAliasView.as_view(), name="user_alias"),
 | 
			
		||||
    path('manage-auth-token/', views.ManageAuthTokens.as_view(), name='auth_token'),
 | 
			
		||||
    # API for the user autocompleter
 | 
			
		||||
    path('user/user-autocomplete', views.UserAutocomplete.as_view(), name="user_autocomplete"),
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,8 @@ from django.views.generic import CreateView, DetailView, UpdateView, TemplateVie
 | 
			
		||||
from django.views.generic.edit import FormMixin
 | 
			
		||||
from django_tables2.views import SingleTableView
 | 
			
		||||
from rest_framework.authtoken.models import Token
 | 
			
		||||
from note.forms import AliasForm, ImageForm
 | 
			
		||||
from note.forms import ImageForm
 | 
			
		||||
#from note.forms import AliasForm, ImageForm
 | 
			
		||||
from note.models import Alias, NoteUser
 | 
			
		||||
from note.models.transactions import Transaction
 | 
			
		||||
from note.tables import HistoryTable, AliasTable
 | 
			
		||||
@@ -143,10 +144,6 @@ class UserDetailView(LoginRequiredMixin, DetailView):
 | 
			
		||||
        club_list = \
 | 
			
		||||
            Membership.objects.all().filter(user=user).only("club")
 | 
			
		||||
        context['club_list'] = ClubTable(club_list)
 | 
			
		||||
        context['title'] = _("Account #%(id)s: %(username)s") % {
 | 
			
		||||
            'id': user.pk,
 | 
			
		||||
            'username': user.username,
 | 
			
		||||
        }
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -172,56 +169,17 @@ class UserListView(LoginRequiredMixin, SingleTableView):
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
class AliasView(LoginRequiredMixin, FormMixin, DetailView):
 | 
			
		||||
class ProfileAliasView(LoginRequiredMixin, DetailView):
 | 
			
		||||
    model = User
 | 
			
		||||
    template_name = 'member/profile_alias.html'
 | 
			
		||||
    context_object_name = 'user_object'
 | 
			
		||||
    form_class = AliasForm
 | 
			
		||||
    
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        context = super().get_context_data(**kwargs)
 | 
			
		||||
        note = context['user_object'].note
 | 
			
		||||
        note = context['object'].note
 | 
			
		||||
        context["aliases"] = AliasTable(note.alias_set.all())
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
    def get_success_url(self):
 | 
			
		||||
        return reverse_lazy('member:user_alias', kwargs={'pk': self.object.id})
 | 
			
		||||
 | 
			
		||||
    def post(self, request, *args, **kwargs):
 | 
			
		||||
        self.object = self.get_object()
 | 
			
		||||
        form = self.get_form()
 | 
			
		||||
        if form.is_valid():
 | 
			
		||||
            return self.form_valid(form)
 | 
			
		||||
        else:
 | 
			
		||||
            return self.form_invalid(form)
 | 
			
		||||
 | 
			
		||||
    def form_valid(self, form):
 | 
			
		||||
        alias = form.save(commit=False)
 | 
			
		||||
        alias.note = self.object.note
 | 
			
		||||
        alias.save()
 | 
			
		||||
        return super().form_valid(form)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DeleteAliasView(LoginRequiredMixin, DeleteView):
 | 
			
		||||
    model = Alias
 | 
			
		||||
 | 
			
		||||
    def delete(self, request, *args, **kwargs):
 | 
			
		||||
        try:
 | 
			
		||||
            self.object = self.get_object()
 | 
			
		||||
            self.object.delete()
 | 
			
		||||
        except ValidationError as e:
 | 
			
		||||
            # TODO: pass message to redirected view.
 | 
			
		||||
            messages.error(self.request, str(e))
 | 
			
		||||
        else:
 | 
			
		||||
            messages.success(self.request, _("Alias successfully deleted"))
 | 
			
		||||
        return HttpResponseRedirect(self.get_success_url())
 | 
			
		||||
 | 
			
		||||
    def get_success_url(self):
 | 
			
		||||
        return reverse_lazy('member:user_alias', kwargs={'pk': self.object.note.user.pk})
 | 
			
		||||
 | 
			
		||||
    def get(self, request, *args, **kwargs):
 | 
			
		||||
        return self.post(request, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PictureUpdateView(LoginRequiredMixin, FormMixin, DetailView):
 | 
			
		||||
    form_class = ImageForm
 | 
			
		||||
@@ -368,6 +326,17 @@ class ClubDetailView(LoginRequiredMixin, DetailView):
 | 
			
		||||
        context['member_list'] = club_member
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
class ClubAliasView(LoginRequiredMixin, DetailView):
 | 
			
		||||
    model = Club
 | 
			
		||||
    template_name = 'member/club_alias.html'
 | 
			
		||||
    context_object_name = 'club'
 | 
			
		||||
    
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        context = super().get_context_data(**kwargs)
 | 
			
		||||
        note = context['object'].note
 | 
			
		||||
        context["aliases"] = AliasTable(note.alias_set.all())
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ClubUpdateView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
    model = Club
 | 
			
		||||
@@ -395,12 +364,12 @@ class ClubAddMemberView(LoginRequiredMixin, CreateView):
 | 
			
		||||
        return super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view")
 | 
			
		||||
                                             | PermissionBackend.filter_queryset(self.request.user, Membership,
 | 
			
		||||
                                                                                 "change"))
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        club = Club.objects.get(pk=self.kwargs["pk"])
 | 
			
		||||
        context = super().get_context_data(**kwargs)
 | 
			
		||||
        context['formset'] = MemberFormSet()
 | 
			
		||||
        context['helper'] = FormSetHelper()
 | 
			
		||||
 | 
			
		||||
        context['club'] = club
 | 
			
		||||
        context['no_cache'] = True
 | 
			
		||||
 | 
			
		||||
        return context
 | 
			
		||||
 
 | 
			
		||||
@@ -78,7 +78,11 @@ class AliasSerializer(serializers.ModelSerializer):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Alias
 | 
			
		||||
        fields = '__all__'
 | 
			
		||||
        read_only_fields = ('note', )
 | 
			
		||||
 | 
			
		||||
    def validate(self, attrs):
 | 
			
		||||
        instance = Alias(**attrs)
 | 
			
		||||
        instance.clean()
 | 
			
		||||
        return attrs
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NotePolymorphicSerializer(PolymorphicSerializer):
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,14 @@
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
from django.db.models import Q
 | 
			
		||||
from django.core.exceptions import ValidationError
 | 
			
		||||
from django_filters.rest_framework import DjangoFilterBackend
 | 
			
		||||
from rest_framework.filters import OrderingFilter, SearchFilter
 | 
			
		||||
from api.viewsets import ReadProtectedModelViewSet, ReadOnlyProtectedModelViewSet
 | 
			
		||||
from rest_framework import viewsets
 | 
			
		||||
from rest_framework.response import Response
 | 
			
		||||
from rest_framework import status
 | 
			
		||||
 | 
			
		||||
from api.viewsets import ReadProtectedModelViewSet, ReadOnlyProtectedModelViewSet
 | 
			
		||||
 | 
			
		||||
from .serializers import NotePolymorphicSerializer, AliasSerializer, TemplateCategorySerializer, \
 | 
			
		||||
    TransactionTemplateSerializer, TransactionPolymorphicSerializer
 | 
			
		||||
@@ -53,6 +57,22 @@ class AliasViewSet(ReadProtectedModelViewSet):
 | 
			
		||||
    search_fields = ['$normalized_name', '$name', '$note__polymorphic_ctype__model', ]
 | 
			
		||||
    ordering_fields = ['name', 'normalized_name']
 | 
			
		||||
 | 
			
		||||
    def get_serializer_class(self):
 | 
			
		||||
        serializer_class = self.serializer_class
 | 
			
		||||
        if self.request.method in ['PUT', 'PATCH']:
 | 
			
		||||
            #alias owner cannot be change once establish
 | 
			
		||||
            setattr(serializer_class.Meta, 'read_only_fields', ('note',))
 | 
			
		||||
        return serializer_class
 | 
			
		||||
    
 | 
			
		||||
    def destroy(self, request, *args, **kwargs):
 | 
			
		||||
        instance = self.get_object()
 | 
			
		||||
        try:
 | 
			
		||||
            self.perform_destroy(instance)
 | 
			
		||||
        except ValidationError as e:
 | 
			
		||||
            print(e)
 | 
			
		||||
            return Response({e.code:e.message},status.HTTP_400_BAD_REQUEST)
 | 
			
		||||
        return Response(status=status.HTTP_204_NO_CONTENT)
 | 
			
		||||
    
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        """
 | 
			
		||||
        Parse query and apply filters.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										58
									
								
								apps/note/fixtures/button.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								apps/note/fixtures/button.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
[
 | 
			
		||||
      {
 | 
			
		||||
    "model": "note.templatecategory",
 | 
			
		||||
    "pk": 1,
 | 
			
		||||
    "fields": {
 | 
			
		||||
      "name": "Soft"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "model": "note.templatecategory",
 | 
			
		||||
    "pk": 2,
 | 
			
		||||
    "fields": {
 | 
			
		||||
      "name": "Pulls"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "model": "note.templatecategory",
 | 
			
		||||
    "pk": 3,
 | 
			
		||||
    "fields": {
 | 
			
		||||
      "name": "Gala"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "model": "note.templatecategory",
 | 
			
		||||
    "pk": 4,
 | 
			
		||||
    "fields": {
 | 
			
		||||
      "name": "Clubs"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "model": "note.templatecategory",
 | 
			
		||||
    "pk": 5,
 | 
			
		||||
    "fields": {
 | 
			
		||||
      "name": "Bouffe"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "model": "note.templatecategory",
 | 
			
		||||
    "pk": 6,
 | 
			
		||||
    "fields": {
 | 
			
		||||
      "name": "BDA"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "model": "note.templatecategory",
 | 
			
		||||
    "pk": 7,
 | 
			
		||||
    "fields": {
 | 
			
		||||
      "name": "Autre"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "model": "note.templatecategory",
 | 
			
		||||
    "pk": 8,
 | 
			
		||||
    "fields": {
 | 
			
		||||
      "name": "Alcool"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
@@ -184,61 +184,5 @@
 | 
			
		||||
      "normalized_name": "kfet",
 | 
			
		||||
      "note": 6
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "model": "note.templatecategory",
 | 
			
		||||
    "pk": 1,
 | 
			
		||||
    "fields": {
 | 
			
		||||
      "name": "Soft"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "model": "note.templatecategory",
 | 
			
		||||
    "pk": 2,
 | 
			
		||||
    "fields": {
 | 
			
		||||
      "name": "Pulls"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "model": "note.templatecategory",
 | 
			
		||||
    "pk": 3,
 | 
			
		||||
    "fields": {
 | 
			
		||||
      "name": "Gala"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "model": "note.templatecategory",
 | 
			
		||||
    "pk": 4,
 | 
			
		||||
    "fields": {
 | 
			
		||||
      "name": "Clubs"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "model": "note.templatecategory",
 | 
			
		||||
    "pk": 5,
 | 
			
		||||
    "fields": {
 | 
			
		||||
      "name": "Bouffe"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "model": "note.templatecategory",
 | 
			
		||||
    "pk": 6,
 | 
			
		||||
    "fields": {
 | 
			
		||||
      "name": "BDA"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "model": "note.templatecategory",
 | 
			
		||||
    "pk": 7,
 | 
			
		||||
    "fields": {
 | 
			
		||||
      "name": "Autre"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "model": "note.templatecategory",
 | 
			
		||||
    "pk": 8,
 | 
			
		||||
    "fields": {
 | 
			
		||||
      "name": "Alcool"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
@@ -9,17 +9,6 @@ from .models import Alias
 | 
			
		||||
from .models import TransactionTemplate
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AliasForm(forms.ModelForm):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Alias
 | 
			
		||||
        fields = ("name",)
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.fields["name"].label = False
 | 
			
		||||
        self.fields["name"].widget.attrs = {"placeholder": _('New Alias')}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ImageForm(forms.Form):
 | 
			
		||||
    image = forms.ImageField(required=False,
 | 
			
		||||
                             label=_('select an image'),
 | 
			
		||||
 
 | 
			
		||||
@@ -228,7 +228,7 @@ class Alias(models.Model):
 | 
			
		||||
                   for cat in {'M', 'P', 'Z', 'C'})).casefold()
 | 
			
		||||
 | 
			
		||||
    def clean(self):
 | 
			
		||||
        normalized_name = Alias.normalize(self.name)
 | 
			
		||||
        normalized_name = self.normalize(self.name)
 | 
			
		||||
        if len(normalized_name) >= 255:
 | 
			
		||||
            raise ValidationError(_('Alias is too long.'),
 | 
			
		||||
                                  code='alias_too_long')
 | 
			
		||||
@@ -242,8 +242,12 @@ class Alias(models.Model):
 | 
			
		||||
            pass
 | 
			
		||||
        self.normalized_name = normalized_name
 | 
			
		||||
 | 
			
		||||
    def save(self,*args,**kwargs):
 | 
			
		||||
        self.normalized_name = self.normalize(self.name)
 | 
			
		||||
        super().save(*args,**kwargs)
 | 
			
		||||
        
 | 
			
		||||
    def delete(self, using=None, keep_parents=False):
 | 
			
		||||
        if self.name == str(self.note):
 | 
			
		||||
            raise ValidationError(_("You can't delete your main alias."),
 | 
			
		||||
                                  code="cant_delete_main_alias")
 | 
			
		||||
                                  code="main_alias")
 | 
			
		||||
        return super().delete(using, keep_parents)
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.db.models import F
 | 
			
		||||
from django.urls import reverse
 | 
			
		||||
from django.utils import timezone
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
@@ -93,12 +94,26 @@ class Transaction(PolymorphicModel):
 | 
			
		||||
        related_name='+',
 | 
			
		||||
        verbose_name=_('source'),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    source_alias = models.CharField(
 | 
			
		||||
        max_length=255,
 | 
			
		||||
        default="",  # Will be remplaced by the name of the note on save
 | 
			
		||||
        verbose_name=_('used alias'),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    destination = models.ForeignKey(
 | 
			
		||||
        Note,
 | 
			
		||||
        on_delete=models.PROTECT,
 | 
			
		||||
        related_name='+',
 | 
			
		||||
        verbose_name=_('destination'),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    destination_alias = models.CharField(
 | 
			
		||||
        max_length=255,
 | 
			
		||||
        default="",  # Will be remplaced by the name of the note on save
 | 
			
		||||
        verbose_name=_('used alias'),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    created_at = models.DateTimeField(
 | 
			
		||||
        verbose_name=_('created at'),
 | 
			
		||||
        default=timezone.now,
 | 
			
		||||
@@ -115,11 +130,19 @@ class Transaction(PolymorphicModel):
 | 
			
		||||
        verbose_name=_('reason'),
 | 
			
		||||
        max_length=255,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    valid = models.BooleanField(
 | 
			
		||||
        verbose_name=_('valid'),
 | 
			
		||||
        default=True,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    invalidity_reason = models.CharField(
 | 
			
		||||
        verbose_name=_('invalidity reason'),
 | 
			
		||||
        max_length=255,
 | 
			
		||||
        default=None,
 | 
			
		||||
        null=True,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        verbose_name = _("transaction")
 | 
			
		||||
        verbose_name_plural = _("transactions")
 | 
			
		||||
@@ -134,6 +157,13 @@ class Transaction(PolymorphicModel):
 | 
			
		||||
        When saving, also transfer money between two notes
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        # If the aliases are not entered, we assume that the used alias is the name of the note
 | 
			
		||||
        if not self.source_alias:
 | 
			
		||||
            self.source_alias = str(self.source)
 | 
			
		||||
 | 
			
		||||
        if not self.destination_alias:
 | 
			
		||||
            self.destination_alias = str(self.destination)
 | 
			
		||||
 | 
			
		||||
        if self.source.pk == self.destination.pk:
 | 
			
		||||
            # When source == destination, no money is transfered
 | 
			
		||||
            super().save(*args, **kwargs)
 | 
			
		||||
@@ -152,6 +182,10 @@ class Transaction(PolymorphicModel):
 | 
			
		||||
            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
 | 
			
		||||
        super().save(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import html
 | 
			
		||||
 | 
			
		||||
import django_tables2 as tables
 | 
			
		||||
from django.db.models import F
 | 
			
		||||
from django.utils.html import format_html
 | 
			
		||||
from django_tables2.utils import A
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
@@ -20,19 +21,48 @@ class HistoryTable(tables.Table):
 | 
			
		||||
                'table table-condensed table-striped table-hover'
 | 
			
		||||
        }
 | 
			
		||||
        model = Transaction
 | 
			
		||||
        exclude = ("id", "polymorphic_ctype", )
 | 
			
		||||
        exclude = ("id", "polymorphic_ctype", "invalidity_reason", "source_alias", "destination_alias",)
 | 
			
		||||
        template_name = 'django_tables2/bootstrap4.html'
 | 
			
		||||
        sequence = ('...', 'type', 'total', 'valid', )
 | 
			
		||||
        sequence = ('...', 'type', 'total', 'valid',)
 | 
			
		||||
        orderable = False
 | 
			
		||||
 | 
			
		||||
    source = tables.Column(
 | 
			
		||||
        attrs={
 | 
			
		||||
            "td": {
 | 
			
		||||
                "data-toggle": "tooltip",
 | 
			
		||||
                "title": lambda record: _("used alias").capitalize() + " : " + record.source_alias,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    destination = tables.Column(
 | 
			
		||||
        attrs={
 | 
			
		||||
            "td": {
 | 
			
		||||
                "data-toggle": "tooltip",
 | 
			
		||||
                "title": lambda record: _("used alias").capitalize() + " : " + record.destination_alias,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    type = tables.Column()
 | 
			
		||||
 | 
			
		||||
    total = tables.Column()  # will use Transaction.total() !!
 | 
			
		||||
 | 
			
		||||
    valid = tables.Column(attrs={"td": {"id": lambda record: "validate_" + str(record.id),
 | 
			
		||||
                                        "class": lambda record: str(record.valid).lower() + ' validate',
 | 
			
		||||
                                        "onclick": lambda record: 'de_validate(' + str(record.id) + ', '
 | 
			
		||||
                                                                  + str(record.valid).lower() + ')'}})
 | 
			
		||||
    valid = tables.Column(
 | 
			
		||||
        attrs={
 | 
			
		||||
            "td": {
 | 
			
		||||
                "id": lambda record: "validate_" + str(record.id),
 | 
			
		||||
                "class": lambda record: str(record.valid).lower() + ' validate',
 | 
			
		||||
                "data-toggle": "tooltip",
 | 
			
		||||
                "title": lambda record: _("Click to invalidate") if record.valid else _("Click to validate"),
 | 
			
		||||
                "onclick": lambda record: 'in_validate(' + str(record.id) + ', ' + str(record.valid).lower() + ')',
 | 
			
		||||
                "onmouseover": lambda record: '$("#invalidity_reason_'
 | 
			
		||||
                                              + str(record.id) + '").show();$("#invalidity_reason_'
 | 
			
		||||
                                              + str(record.id) + '").focus();',
 | 
			
		||||
                "onmouseout": lambda record: '$("#invalidity_reason_' + str(record.id) + '").hide()',
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def order_total(self, queryset, is_descending):
 | 
			
		||||
        # needed for rendering
 | 
			
		||||
@@ -53,13 +83,23 @@ class HistoryTable(tables.Table):
 | 
			
		||||
    def render_reason(self, value):
 | 
			
		||||
        return html.unescape(value)
 | 
			
		||||
 | 
			
		||||
    def render_valid(self, value):
 | 
			
		||||
        return "✔" if value else "✖"
 | 
			
		||||
    def render_valid(self, value, record):
 | 
			
		||||
        """
 | 
			
		||||
        When the validation status is hovered, an input field is displayed to let the user specify an invalidity reason
 | 
			
		||||
        """
 | 
			
		||||
        val = "✔" if value else "✖"
 | 
			
		||||
        val += "<input type='text' class='form-control' id='invalidity_reason_" + str(record.id) \
 | 
			
		||||
               + "' value='" + (html.escape(record.invalidity_reason)
 | 
			
		||||
                                if record.invalidity_reason else ("" if value else str(_("No reason specified")))) \
 | 
			
		||||
               + "'" + ("" if value else " disabled") \
 | 
			
		||||
               + " placeholder='" + html.escape(_("invalidity reason").capitalize()) + "'" \
 | 
			
		||||
               + " style='position: absolute; width: 15em; margin-left: -15.5em; margin-top: -2em; display: none;'>"
 | 
			
		||||
        return format_html(val)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# function delete_button(id) provided in template file
 | 
			
		||||
DELETE_TEMPLATE = """
 | 
			
		||||
    <button id="{{ record.pk }}" class="btn btn-danger" onclick="delete_button(this.id)"> {{ delete_trans }}</button>
 | 
			
		||||
    <button id="{{ record.pk }}" class="btn btn-danger btn-sm" onclick="delete_button(this.id)"> {{ delete_trans }}</button>
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -67,7 +107,8 @@ class AliasTable(tables.Table):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        attrs = {
 | 
			
		||||
            'class':
 | 
			
		||||
                'table table condensed table-striped table-hover'
 | 
			
		||||
                'table table condensed table-striped table-hover',
 | 
			
		||||
            'id':"alias_table"
 | 
			
		||||
        }
 | 
			
		||||
        model = Alias
 | 
			
		||||
        fields = ('name',)
 | 
			
		||||
@@ -75,15 +116,11 @@ class AliasTable(tables.Table):
 | 
			
		||||
 | 
			
		||||
    show_header = False
 | 
			
		||||
    name = tables.Column(attrs={'td': {'class': 'text-center'}})
 | 
			
		||||
    # delete = tables.TemplateColumn(template_code=delete_template,
 | 
			
		||||
    #                                attrs={'td':{'class': 'col-sm-1'}})
 | 
			
		||||
 | 
			
		||||
    delete = tables.LinkColumn('member:user_alias_delete',
 | 
			
		||||
                               args=[A('pk')],
 | 
			
		||||
                               attrs={
 | 
			
		||||
                                   'td': {'class': 'col-sm-2'},
 | 
			
		||||
                                   'a': {'class': 'btn btn-danger'}},
 | 
			
		||||
                               text='delete', accessor='pk')
 | 
			
		||||
    delete_col = tables.TemplateColumn(template_code=DELETE_TEMPLATE,
 | 
			
		||||
                                   extra_context={"delete_trans": _('delete')},
 | 
			
		||||
                                   attrs={'td': {'class': 'col-sm-1'}})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ButtonTable(tables.Table):
 | 
			
		||||
@@ -103,11 +140,11 @@ class ButtonTable(tables.Table):
 | 
			
		||||
    edit = tables.LinkColumn('note:template_update',
 | 
			
		||||
                             args=[A('pk')],
 | 
			
		||||
                             attrs={'td': {'class': 'col-sm-1'},
 | 
			
		||||
                                    'a': {'class': 'btn btn-primary'}},
 | 
			
		||||
                                    'a': {'class': 'btn btn-sm btn-primary'}},
 | 
			
		||||
                             text=_('edit'),
 | 
			
		||||
                             accessor='pk')
 | 
			
		||||
 | 
			
		||||
    delete = tables.TemplateColumn(template_code=DELETE_TEMPLATE,
 | 
			
		||||
    delete_col = tables.TemplateColumn(template_code=DELETE_TEMPLATE,
 | 
			
		||||
                                   extra_context={"delete_trans": _('delete')},
 | 
			
		||||
                                   attrs={'td': {'class': 'col-sm-1'}})
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -327,7 +327,7 @@
 | 
			
		||||
        "note",
 | 
			
		||||
        "transaction"
 | 
			
		||||
      ],
 | 
			
		||||
      "query": "[\"AND\", {\"source\": [\"user\", \"note\"]}, {\"amount__lte\": [\"user\", \"note\", \"balance\"]}]",
 | 
			
		||||
      "query": "[\"AND\", {\"source\": [\"user\", \"note\"]}, [\"OR\", {\"amount__lte\": [\"user\", \"note\", \"balance\"]}, {\"valid\": false}]]",
 | 
			
		||||
      "type": "add",
 | 
			
		||||
      "mask": 1,
 | 
			
		||||
      "field": "",
 | 
			
		||||
@@ -387,7 +387,7 @@
 | 
			
		||||
        "note",
 | 
			
		||||
        "recurrenttransaction"
 | 
			
		||||
      ],
 | 
			
		||||
      "query": "[\"AND\", {\"destination\": [\"club\", \"note\"]}, {\"amount__lte\": {\"F\": [\"ADD\", [\"F\", \"source__balance\"], 5000]}}]",
 | 
			
		||||
      "query": "[\"AND\", {\"destination\": [\"club\", \"note\"]}, [\"OR\", {\"amount__lte\": {\"F\": [\"ADD\", [\"F\", \"source__balance\"], 5000]}}, {\"valid\": false}]]",
 | 
			
		||||
      "type": "add",
 | 
			
		||||
      "mask": 2,
 | 
			
		||||
      "field": "",
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: PACKAGE VERSION\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2020-03-24 15:49+0100\n"
 | 
			
		||||
"POT-Creation-Date: 2020-03-26 14:40+0100\n"
 | 
			
		||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 | 
			
		||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 | 
			
		||||
"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
			
		||||
@@ -24,8 +24,8 @@ msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/activity/models.py:19 apps/activity/models.py:44
 | 
			
		||||
#: apps/member/models.py:63 apps/member/models.py:114
 | 
			
		||||
#: apps/note/models/notes.py:188 apps/note/models/transactions.py:24
 | 
			
		||||
#: apps/note/models/transactions.py:44 apps/note/models/transactions.py:198
 | 
			
		||||
#: apps/note/models/notes.py:188 apps/note/models/transactions.py:25
 | 
			
		||||
#: apps/note/models/transactions.py:45 apps/note/models/transactions.py:232
 | 
			
		||||
#: templates/member/profile_detail.html:15
 | 
			
		||||
msgid "name"
 | 
			
		||||
msgstr ""
 | 
			
		||||
@@ -46,13 +46,13 @@ msgstr ""
 | 
			
		||||
msgid "activity types"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/activity/models.py:48 apps/note/models/transactions.py:69
 | 
			
		||||
#: apps/permission/models.py:90
 | 
			
		||||
#: apps/activity/models.py:48 apps/note/models/transactions.py:70
 | 
			
		||||
#: apps/permission/models.py:91
 | 
			
		||||
msgid "description"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/activity/models.py:54 apps/note/models/notes.py:164
 | 
			
		||||
#: apps/note/models/transactions.py:62
 | 
			
		||||
#: apps/note/models/transactions.py:63
 | 
			
		||||
msgid "type"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
@@ -120,11 +120,11 @@ msgstr ""
 | 
			
		||||
msgid "create"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/logs/models.py:61
 | 
			
		||||
#: apps/logs/models.py:61 apps/note/tables.py:147
 | 
			
		||||
msgid "edit"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/logs/models.py:62
 | 
			
		||||
#: apps/logs/models.py:62 apps/note/tables.py:151
 | 
			
		||||
msgid "delete"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
@@ -210,7 +210,7 @@ msgstr ""
 | 
			
		||||
msgid "clubs"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/member/models.py:120 apps/permission/models.py:275
 | 
			
		||||
#: apps/member/models.py:120 apps/permission/models.py:276
 | 
			
		||||
msgid "role"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
@@ -255,12 +255,12 @@ msgstr ""
 | 
			
		||||
msgid "Alias successfully deleted"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/admin.py:120 apps/note/models/transactions.py:94
 | 
			
		||||
#: apps/note/admin.py:120 apps/note/models/transactions.py:95
 | 
			
		||||
msgid "source"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/admin.py:128 apps/note/admin.py:156
 | 
			
		||||
#: apps/note/models/transactions.py:53 apps/note/models/transactions.py:100
 | 
			
		||||
#: apps/note/models/transactions.py:54 apps/note/models/transactions.py:108
 | 
			
		||||
msgid "destination"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
@@ -310,7 +310,7 @@ msgstr ""
 | 
			
		||||
msgid "display image"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/notes.py:53 apps/note/models/transactions.py:103
 | 
			
		||||
#: apps/note/models/notes.py:53 apps/note/models/transactions.py:118
 | 
			
		||||
msgid "created at"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
@@ -384,55 +384,64 @@ msgstr ""
 | 
			
		||||
msgid "You can't delete your main alias."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:30
 | 
			
		||||
#: apps/note/models/transactions.py:31
 | 
			
		||||
msgid "transaction category"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:31
 | 
			
		||||
#: apps/note/models/transactions.py:32
 | 
			
		||||
msgid "transaction categories"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:47
 | 
			
		||||
#: apps/note/models/transactions.py:48
 | 
			
		||||
msgid "A template with this name already exist"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:56 apps/note/models/transactions.py:111
 | 
			
		||||
#: apps/note/models/transactions.py:57 apps/note/models/transactions.py:126
 | 
			
		||||
msgid "amount"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:57
 | 
			
		||||
#: apps/note/models/transactions.py:58
 | 
			
		||||
msgid "in centimes"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:75
 | 
			
		||||
#: apps/note/models/transactions.py:76
 | 
			
		||||
msgid "transaction template"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:76
 | 
			
		||||
#: apps/note/models/transactions.py:77
 | 
			
		||||
msgid "transaction templates"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:107
 | 
			
		||||
#: apps/note/models/transactions.py:101 apps/note/models/transactions.py:114
 | 
			
		||||
#: apps/note/tables.py:33 apps/note/tables.py:42
 | 
			
		||||
msgid "used alias"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:122
 | 
			
		||||
msgid "quantity"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:115
 | 
			
		||||
#: apps/note/models/transactions.py:130
 | 
			
		||||
msgid "reason"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:119
 | 
			
		||||
#: apps/note/models/transactions.py:135
 | 
			
		||||
msgid "valid"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:124
 | 
			
		||||
#: apps/note/models/transactions.py:140 apps/note/tables.py:95
 | 
			
		||||
msgid "invalidity reason"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:147
 | 
			
		||||
msgid "transaction"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:125
 | 
			
		||||
#: apps/note/models/transactions.py:148
 | 
			
		||||
msgid "transactions"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:168 templates/base.html:98
 | 
			
		||||
#: apps/note/models/transactions.py:202 templates/base.html:83
 | 
			
		||||
#: templates/note/transaction_form.html:19
 | 
			
		||||
#: templates/note/transaction_form.html:145
 | 
			
		||||
msgid "Transfer"
 | 
			
		||||
@@ -634,15 +643,15 @@ msgid ""
 | 
			
		||||
"again unless your session expires or you logout."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: note_kfet/settings/base.py:153
 | 
			
		||||
#: note_kfet/settings/base.py:151
 | 
			
		||||
msgid "German"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: note_kfet/settings/base.py:154
 | 
			
		||||
#: note_kfet/settings/base.py:152
 | 
			
		||||
msgid "English"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: note_kfet/settings/base.py:155
 | 
			
		||||
#: note_kfet/settings/base.py:153
 | 
			
		||||
msgid "French"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
@@ -650,18 +659,14 @@ msgstr ""
 | 
			
		||||
msgid "The ENS Paris-Saclay BDE note."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/base.html:84
 | 
			
		||||
#: templates/base.html:87
 | 
			
		||||
msgid "Clubs"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/base.html:89
 | 
			
		||||
#: templates/base.html:92
 | 
			
		||||
msgid "Activities"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/base.html:94
 | 
			
		||||
msgid "Buttons"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/cas_server/base.html:7
 | 
			
		||||
msgid "Central Authentication Service"
 | 
			
		||||
msgstr ""
 | 
			
		||||
@@ -798,7 +803,7 @@ msgstr ""
 | 
			
		||||
msgid "Sign up"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/note/conso_form.html:28 templates/note/transaction_form.html:40
 | 
			
		||||
#: templates/note/conso_form.html:28 templates/note/transaction_form.html:50
 | 
			
		||||
msgid "Select emitters"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
@@ -842,12 +847,28 @@ msgstr ""
 | 
			
		||||
msgid "Transfer type"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/note/transaction_form.html:86
 | 
			
		||||
msgid "Name"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/note/transaction_form.html:92
 | 
			
		||||
msgid "First name"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/note/transaction_form.html:98
 | 
			
		||||
msgid "Bank"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/note/transaction_form.html:111
 | 
			
		||||
#: templates/note/transaction_form.html:169
 | 
			
		||||
#: templates/note/transaction_form.html:176
 | 
			
		||||
msgid "Select receivers"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/note/transaction_form.html:128
 | 
			
		||||
msgid "Amount"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/note/transaction_form.html:138
 | 
			
		||||
msgid "Reason"
 | 
			
		||||
msgstr ""
 | 
			
		||||
@@ -864,6 +885,22 @@ msgstr ""
 | 
			
		||||
msgid "Buttons list"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/note/transactiontemplate_list.html:9
 | 
			
		||||
msgid "search button"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/note/transactiontemplate_list.html:20
 | 
			
		||||
msgid "buttons listing "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/note/transactiontemplate_list.html:71
 | 
			
		||||
msgid "button successfully deleted "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/note/transactiontemplate_list.html:75
 | 
			
		||||
msgid "Unable to delete button "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/registration/logged_out.html:8
 | 
			
		||||
msgid "Thanks for spending some quality time with the Web site today."
 | 
			
		||||
msgstr ""
 | 
			
		||||
@@ -873,7 +910,7 @@ msgid "Log in again"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/registration/login.html:7 templates/registration/login.html:8
 | 
			
		||||
#: templates/registration/login.html:26
 | 
			
		||||
#: templates/registration/login.html:28
 | 
			
		||||
#: templates/registration/password_reset_complete.html:10
 | 
			
		||||
msgid "Log in"
 | 
			
		||||
msgstr ""
 | 
			
		||||
@@ -885,7 +922,15 @@ msgid ""
 | 
			
		||||
"page. Would you like to login to a different account?"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/registration/login.html:27
 | 
			
		||||
#: templates/registration/login.html:22
 | 
			
		||||
msgid "You can also register via the central authentification server "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/registration/login.html:23
 | 
			
		||||
msgid "using this link "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/registration/login.html:29
 | 
			
		||||
msgid "Forgotten your password or username?"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: PACKAGE VERSION\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2020-03-24 15:49+0100\n"
 | 
			
		||||
"POT-Creation-Date: 2020-03-26 14:40+0100\n"
 | 
			
		||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 | 
			
		||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 | 
			
		||||
"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
			
		||||
@@ -19,8 +19,8 @@ msgstr "activité"
 | 
			
		||||
 | 
			
		||||
#: apps/activity/models.py:19 apps/activity/models.py:44
 | 
			
		||||
#: apps/member/models.py:63 apps/member/models.py:114
 | 
			
		||||
#: apps/note/models/notes.py:188 apps/note/models/transactions.py:24
 | 
			
		||||
#: apps/note/models/transactions.py:44 apps/note/models/transactions.py:198
 | 
			
		||||
#: apps/note/models/notes.py:188 apps/note/models/transactions.py:25
 | 
			
		||||
#: apps/note/models/transactions.py:45 apps/note/models/transactions.py:232
 | 
			
		||||
#: templates/member/profile_detail.html:15
 | 
			
		||||
msgid "name"
 | 
			
		||||
msgstr "nom"
 | 
			
		||||
@@ -41,13 +41,13 @@ msgstr "type d'activité"
 | 
			
		||||
msgid "activity types"
 | 
			
		||||
msgstr "types d'activité"
 | 
			
		||||
 | 
			
		||||
#: apps/activity/models.py:48 apps/note/models/transactions.py:69
 | 
			
		||||
#: apps/permission/models.py:90
 | 
			
		||||
#: apps/activity/models.py:48 apps/note/models/transactions.py:70
 | 
			
		||||
#: apps/permission/models.py:91
 | 
			
		||||
msgid "description"
 | 
			
		||||
msgstr "description"
 | 
			
		||||
 | 
			
		||||
#: apps/activity/models.py:54 apps/note/models/notes.py:164
 | 
			
		||||
#: apps/note/models/transactions.py:62
 | 
			
		||||
#: apps/note/models/transactions.py:63
 | 
			
		||||
msgid "type"
 | 
			
		||||
msgstr "type"
 | 
			
		||||
 | 
			
		||||
@@ -115,11 +115,11 @@ msgstr "Nouvelles données"
 | 
			
		||||
msgid "create"
 | 
			
		||||
msgstr "Créer"
 | 
			
		||||
 | 
			
		||||
#: apps/logs/models.py:61
 | 
			
		||||
#: apps/logs/models.py:61 apps/note/tables.py:147
 | 
			
		||||
msgid "edit"
 | 
			
		||||
msgstr "Modifier"
 | 
			
		||||
 | 
			
		||||
#: apps/logs/models.py:62
 | 
			
		||||
#: apps/logs/models.py:62 apps/note/tables.py:151
 | 
			
		||||
msgid "delete"
 | 
			
		||||
msgstr "Supprimer"
 | 
			
		||||
 | 
			
		||||
@@ -209,7 +209,7 @@ msgstr "club"
 | 
			
		||||
msgid "clubs"
 | 
			
		||||
msgstr "clubs"
 | 
			
		||||
 | 
			
		||||
#: apps/member/models.py:120 apps/permission/models.py:275
 | 
			
		||||
#: apps/member/models.py:120 apps/permission/models.py:276
 | 
			
		||||
msgid "role"
 | 
			
		||||
msgstr "rôle"
 | 
			
		||||
 | 
			
		||||
@@ -254,12 +254,12 @@ msgstr "Compte n°%(id)s : %(username)s"
 | 
			
		||||
msgid "Alias successfully deleted"
 | 
			
		||||
msgstr "L'alias a bien été supprimé"
 | 
			
		||||
 | 
			
		||||
#: apps/note/admin.py:120 apps/note/models/transactions.py:94
 | 
			
		||||
#: apps/note/admin.py:120 apps/note/models/transactions.py:95
 | 
			
		||||
msgid "source"
 | 
			
		||||
msgstr "source"
 | 
			
		||||
 | 
			
		||||
#: apps/note/admin.py:128 apps/note/admin.py:156
 | 
			
		||||
#: apps/note/models/transactions.py:53 apps/note/models/transactions.py:100
 | 
			
		||||
#: apps/note/models/transactions.py:54 apps/note/models/transactions.py:108
 | 
			
		||||
msgid "destination"
 | 
			
		||||
msgstr "destination"
 | 
			
		||||
 | 
			
		||||
@@ -310,7 +310,7 @@ msgstr ""
 | 
			
		||||
msgid "display image"
 | 
			
		||||
msgstr "image affichée"
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/notes.py:53 apps/note/models/transactions.py:103
 | 
			
		||||
#: apps/note/models/notes.py:53 apps/note/models/transactions.py:118
 | 
			
		||||
msgid "created at"
 | 
			
		||||
msgstr "créée le"
 | 
			
		||||
 | 
			
		||||
@@ -384,35 +384,40 @@ msgstr "Un alias avec un nom similaire existe déjà : {}"
 | 
			
		||||
msgid "You can't delete your main alias."
 | 
			
		||||
msgstr "Vous ne pouvez pas supprimer votre alias principal."
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:30
 | 
			
		||||
#: apps/note/models/transactions.py:31
 | 
			
		||||
msgid "transaction category"
 | 
			
		||||
msgstr "catégorie de transaction"
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:31
 | 
			
		||||
#: apps/note/models/transactions.py:32
 | 
			
		||||
msgid "transaction categories"
 | 
			
		||||
msgstr "catégories de transaction"
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:47
 | 
			
		||||
#: apps/note/models/transactions.py:48
 | 
			
		||||
msgid "A template with this name already exist"
 | 
			
		||||
msgstr "Un modèle de transaction avec un nom similaire existe déjà."
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:56 apps/note/models/transactions.py:111
 | 
			
		||||
#: apps/note/models/transactions.py:57 apps/note/models/transactions.py:126
 | 
			
		||||
msgid "amount"
 | 
			
		||||
msgstr "montant"
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:57
 | 
			
		||||
#: apps/note/models/transactions.py:58
 | 
			
		||||
msgid "in centimes"
 | 
			
		||||
msgstr "en centimes"
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:75
 | 
			
		||||
#: apps/note/models/transactions.py:76
 | 
			
		||||
msgid "transaction template"
 | 
			
		||||
msgstr "modèle de transaction"
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:76
 | 
			
		||||
#: apps/note/models/transactions.py:77
 | 
			
		||||
msgid "transaction templates"
 | 
			
		||||
msgstr "modèles de transaction"
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:107
 | 
			
		||||
#: apps/note/models/transactions.py:101 apps/note/models/transactions.py:114
 | 
			
		||||
#: apps/note/tables.py:33 apps/note/tables.py:42
 | 
			
		||||
msgid "used alias"
 | 
			
		||||
msgstr "alias utilisé"
 | 
			
		||||
 | 
			
		||||
#: apps/note/models/transactions.py:122
 | 
			
		||||
msgid "quantity"
 | 
			
		||||
msgstr "quantité"
 | 
			
		||||
 | 
			
		||||
@@ -634,15 +639,15 @@ msgid ""
 | 
			
		||||
"again unless your session expires or you logout."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: note_kfet/settings/base.py:153
 | 
			
		||||
#: note_kfet/settings/base.py:151
 | 
			
		||||
msgid "German"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: note_kfet/settings/base.py:154
 | 
			
		||||
#: note_kfet/settings/base.py:152
 | 
			
		||||
msgid "English"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: note_kfet/settings/base.py:155
 | 
			
		||||
#: note_kfet/settings/base.py:153
 | 
			
		||||
msgid "French"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
@@ -650,18 +655,14 @@ msgstr ""
 | 
			
		||||
msgid "The ENS Paris-Saclay BDE note."
 | 
			
		||||
msgstr "La note du BDE de l'ENS Paris-Saclay."
 | 
			
		||||
 | 
			
		||||
#: templates/base.html:84
 | 
			
		||||
#: templates/base.html:87
 | 
			
		||||
msgid "Clubs"
 | 
			
		||||
msgstr "Clubs"
 | 
			
		||||
 | 
			
		||||
#: templates/base.html:89
 | 
			
		||||
#: templates/base.html:92
 | 
			
		||||
msgid "Activities"
 | 
			
		||||
msgstr "Activités"
 | 
			
		||||
 | 
			
		||||
#: templates/base.html:94
 | 
			
		||||
msgid "Buttons"
 | 
			
		||||
msgstr "Boutons"
 | 
			
		||||
 | 
			
		||||
#: templates/cas_server/base.html:7
 | 
			
		||||
msgid "Central Authentication Service"
 | 
			
		||||
msgstr ""
 | 
			
		||||
@@ -800,7 +801,7 @@ msgstr "Sauvegarder les changements"
 | 
			
		||||
msgid "Sign up"
 | 
			
		||||
msgstr "Inscription"
 | 
			
		||||
 | 
			
		||||
#: templates/note/conso_form.html:28 templates/note/transaction_form.html:40
 | 
			
		||||
#: templates/note/conso_form.html:28 templates/note/transaction_form.html:50
 | 
			
		||||
msgid "Select emitters"
 | 
			
		||||
msgstr "Sélection des émetteurs"
 | 
			
		||||
 | 
			
		||||
@@ -844,12 +845,28 @@ msgstr "Paiement externe"
 | 
			
		||||
msgid "Transfer type"
 | 
			
		||||
msgstr "Type de transfert"
 | 
			
		||||
 | 
			
		||||
#: templates/note/transaction_form.html:86
 | 
			
		||||
msgid "Name"
 | 
			
		||||
msgstr "Nom"
 | 
			
		||||
 | 
			
		||||
#: templates/note/transaction_form.html:92
 | 
			
		||||
msgid "First name"
 | 
			
		||||
msgstr "Prénom"
 | 
			
		||||
 | 
			
		||||
#: templates/note/transaction_form.html:98
 | 
			
		||||
msgid "Bank"
 | 
			
		||||
msgstr "Banque"
 | 
			
		||||
 | 
			
		||||
#: templates/note/transaction_form.html:111
 | 
			
		||||
#: templates/note/transaction_form.html:169
 | 
			
		||||
#: templates/note/transaction_form.html:176
 | 
			
		||||
msgid "Select receivers"
 | 
			
		||||
msgstr "Sélection des destinataires"
 | 
			
		||||
 | 
			
		||||
#: templates/note/transaction_form.html:128
 | 
			
		||||
msgid "Amount"
 | 
			
		||||
msgstr "Montant"
 | 
			
		||||
 | 
			
		||||
#: templates/note/transaction_form.html:138
 | 
			
		||||
msgid "Reason"
 | 
			
		||||
msgstr "Raison"
 | 
			
		||||
@@ -866,6 +883,22 @@ msgstr "Note à débiter"
 | 
			
		||||
msgid "Buttons list"
 | 
			
		||||
msgstr "Liste des boutons"
 | 
			
		||||
 | 
			
		||||
#: templates/note/transactiontemplate_list.html:9
 | 
			
		||||
msgid "search button"
 | 
			
		||||
msgstr "Chercher un bouton"
 | 
			
		||||
 | 
			
		||||
#: templates/note/transactiontemplate_list.html:20
 | 
			
		||||
msgid "buttons listing "
 | 
			
		||||
msgstr "Liste des boutons"
 | 
			
		||||
 | 
			
		||||
#: templates/note/transactiontemplate_list.html:71
 | 
			
		||||
msgid "button successfully deleted "
 | 
			
		||||
msgstr "Le bouton a bien été supprimé"
 | 
			
		||||
 | 
			
		||||
#: templates/note/transactiontemplate_list.html:75
 | 
			
		||||
msgid "Unable to delete button "
 | 
			
		||||
msgstr "Impossible de supprimer le bouton "
 | 
			
		||||
 | 
			
		||||
#: templates/registration/logged_out.html:8
 | 
			
		||||
msgid "Thanks for spending some quality time with the Web site today."
 | 
			
		||||
msgstr ""
 | 
			
		||||
@@ -875,7 +908,7 @@ msgid "Log in again"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/registration/login.html:7 templates/registration/login.html:8
 | 
			
		||||
#: templates/registration/login.html:26
 | 
			
		||||
#: templates/registration/login.html:28
 | 
			
		||||
#: templates/registration/password_reset_complete.html:10
 | 
			
		||||
msgid "Log in"
 | 
			
		||||
msgstr ""
 | 
			
		||||
@@ -887,7 +920,15 @@ msgid ""
 | 
			
		||||
"page. Would you like to login to a different account?"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/registration/login.html:27
 | 
			
		||||
#: templates/registration/login.html:22
 | 
			
		||||
msgid "You can also register via the central authentification server "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/registration/login.html:23
 | 
			
		||||
msgid "using this link "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/registration/login.html:29
 | 
			
		||||
msgid "Forgotten your password or username?"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										37
									
								
								static/js/alias.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								static/js/alias.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
 | 
			
		||||
 $("#alias_input").on('keypress',function(e) {
 | 
			
		||||
     if(e.which == 13) {
 | 
			
		||||
         $("#alias_submit").click();
 | 
			
		||||
     }
 | 
			
		||||
 });
 | 
			
		||||
 | 
			
		||||
 function create_alias(note_id){
 | 
			
		||||
     $.post("/api/note/alias/",
 | 
			
		||||
            {
 | 
			
		||||
                "csrfmiddlewaretoken": CSRF_TOKEN,
 | 
			
		||||
                "name": $("#alias_input").val(),
 | 
			
		||||
                "note": note_id
 | 
			
		||||
            }
 | 
			
		||||
     ).done(function(){
 | 
			
		||||
         $("#alias_table").load(location.href+ " #alias_table");
 | 
			
		||||
         addMsg("Alias ajouté","success");
 | 
			
		||||
     })
 | 
			
		||||
      .fail(function(xhr, textStatus, error){
 | 
			
		||||
          errMsg(xhr.responseJSON);
 | 
			
		||||
      });
 | 
			
		||||
}
 | 
			
		||||
 // on click of button "delete" , call the API
 | 
			
		||||
 function delete_button(button_id){
 | 
			
		||||
     $.ajax({
 | 
			
		||||
         url:"/api/note/alias/"+button_id+"/",
 | 
			
		||||
         method:"DELETE",
 | 
			
		||||
         headers: {"X-CSRFTOKEN": CSRF_TOKEN}
 | 
			
		||||
     })
 | 
			
		||||
      .done(function(){
 | 
			
		||||
          addMsg('Alias supprimé','success');
 | 
			
		||||
          $("#alias_table").load(location.href + " #alias_table");
 | 
			
		||||
      })
 | 
			
		||||
      .fail(function(xhr,textStatus, error){
 | 
			
		||||
          errMsg(xhr.responseJSON);
 | 
			
		||||
      });
 | 
			
		||||
 }
 | 
			
		||||
@@ -28,7 +28,15 @@ function addMsg(msg, alert_type) {
 | 
			
		||||
        + msg + "</div>\n";
 | 
			
		||||
    msgDiv.html(html);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * add Muliple error message from err_obj
 | 
			
		||||
 * @param err_obj {error_code:erro_message}
 | 
			
		||||
 */
 | 
			
		||||
function errMsg(errs_obj){
 | 
			
		||||
    for (const err_msg of Object.values(errs_obj)) {
 | 
			
		||||
              addMsg(err_msg,'danger');
 | 
			
		||||
          }
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * Reload the balance of the user on the right top corner
 | 
			
		||||
 */
 | 
			
		||||
@@ -265,7 +273,16 @@ function autoCompleteNote(field_id, alias_matched_id, note_list_id, notes, notes
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// When a validate button is clicked, we switch the validation status
 | 
			
		||||
function de_validate(id, validated) {
 | 
			
		||||
function in_validate(id, validated) {
 | 
			
		||||
 | 
			
		||||
    let invalidity_reason;
 | 
			
		||||
    let reason_obj = $("#invalidity_reason_" + id);
 | 
			
		||||
 | 
			
		||||
    if (validated)
 | 
			
		||||
        invalidity_reason = reason_obj.val();
 | 
			
		||||
    else
 | 
			
		||||
        invalidity_reason = null;
 | 
			
		||||
 | 
			
		||||
    $("#validate_" + id).html("<strong style=\"font-size: 16pt;\">⟳ ...</strong>");
 | 
			
		||||
 | 
			
		||||
    // Perform a PATCH request to the API in order to update the transaction
 | 
			
		||||
@@ -278,12 +295,13 @@ function de_validate(id, validated) {
 | 
			
		||||
            "X-CSRFTOKEN": CSRF_TOKEN
 | 
			
		||||
        },
 | 
			
		||||
        data: {
 | 
			
		||||
            "resourcetype": "RecurrentTransaction",
 | 
			
		||||
            valid: !validated
 | 
			
		||||
            resourcetype: "RecurrentTransaction",
 | 
			
		||||
            valid: !validated,
 | 
			
		||||
            invalidity_reason: invalidity_reason,
 | 
			
		||||
        },
 | 
			
		||||
        success: function () {
 | 
			
		||||
            // Refresh jQuery objects
 | 
			
		||||
            $(".validate").click(de_validate);
 | 
			
		||||
            $(".validate").click(in_validate);
 | 
			
		||||
 | 
			
		||||
            refreshBalance();
 | 
			
		||||
            // error if this method doesn't exist. Please define it.
 | 
			
		||||
 
 | 
			
		||||
@@ -167,7 +167,7 @@ function reset() {
 | 
			
		||||
function consumeAll() {
 | 
			
		||||
    notes_display.forEach(function(note_display) {
 | 
			
		||||
        buttons.forEach(function(button) {
 | 
			
		||||
            consume(note_display.id, button.dest, button.quantity * note_display.quantity, button.amount,
 | 
			
		||||
            consume(note_display.id, note_display.name, button.dest, button.quantity * note_display.quantity, button.amount,
 | 
			
		||||
                button.name + " (" + button.category_name + ")", button.type, button.category_id, button.id);
 | 
			
		||||
       });
 | 
			
		||||
    });
 | 
			
		||||
@@ -176,6 +176,7 @@ function consumeAll() {
 | 
			
		||||
/**
 | 
			
		||||
 * Create a new transaction from a button through the API.
 | 
			
		||||
 * @param source The note that paid the item (type: int)
 | 
			
		||||
 * @param source_alias The alias used for the source (type: str)
 | 
			
		||||
 * @param dest The note that sold the item (type: int)
 | 
			
		||||
 * @param quantity The quantity sold (type: int)
 | 
			
		||||
 * @param amount The price of one item, in cents (type: int)
 | 
			
		||||
@@ -184,7 +185,7 @@ function consumeAll() {
 | 
			
		||||
 * @param category The category id of the button (type: int)
 | 
			
		||||
 * @param template The button id (type: int)
 | 
			
		||||
 */
 | 
			
		||||
function consume(source, dest, quantity, amount, reason, type, category, template) {
 | 
			
		||||
function consume(source, source_alias, dest, quantity, amount, reason, type, category, template) {
 | 
			
		||||
    $.post("/api/note/transaction/transaction/",
 | 
			
		||||
        {
 | 
			
		||||
            "csrfmiddlewaretoken": CSRF_TOKEN,
 | 
			
		||||
@@ -195,12 +196,32 @@ function consume(source, dest, quantity, amount, reason, type, category, templat
 | 
			
		||||
            "polymorphic_ctype": type,
 | 
			
		||||
            "resourcetype": "RecurrentTransaction",
 | 
			
		||||
            "source": source,
 | 
			
		||||
            "source_alias": source_alias,
 | 
			
		||||
            "destination": dest,
 | 
			
		||||
            "category": category,
 | 
			
		||||
            "template": template
 | 
			
		||||
        }, reset).fail(function (e) {
 | 
			
		||||
            reset();
 | 
			
		||||
 | 
			
		||||
            addMsg("Une erreur est survenue lors de la transaction : " + e.responseText, "danger");
 | 
			
		||||
            $.post("/api/note/transaction/transaction/",
 | 
			
		||||
            {
 | 
			
		||||
                "csrfmiddlewaretoken": CSRF_TOKEN,
 | 
			
		||||
                "quantity": quantity,
 | 
			
		||||
                "amount": amount,
 | 
			
		||||
                "reason": reason,
 | 
			
		||||
                "valid": false,
 | 
			
		||||
                "invalidity_reason": "Solde insuffisant",
 | 
			
		||||
                "polymorphic_ctype": type,
 | 
			
		||||
                "resourcetype": "RecurrentTransaction",
 | 
			
		||||
                "source": source,
 | 
			
		||||
                "source_alias": source_alias,
 | 
			
		||||
                "destination": dest,
 | 
			
		||||
                "category": category,
 | 
			
		||||
                "template": template
 | 
			
		||||
            }).done(function() {
 | 
			
		||||
                reset();
 | 
			
		||||
                addMsg("La transaction n'a pas pu être validée pour cause de solde insuffisant.", "danger");
 | 
			
		||||
            }).fail(function () {
 | 
			
		||||
                reset();
 | 
			
		||||
                errMsg(e.responseJSON);
 | 
			
		||||
            });
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -83,19 +83,41 @@ $("#transfer").click(function() {
 | 
			
		||||
                    "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
 | 
			
		||||
                    "resourcetype": "Transaction",
 | 
			
		||||
                    "source": user_id,
 | 
			
		||||
                    "destination": dest.id
 | 
			
		||||
                }, function () {
 | 
			
		||||
                    "destination": dest.id,
 | 
			
		||||
                    "destination_alias": dest.name
 | 
			
		||||
                }).done(function () {
 | 
			
		||||
                    addMsg("Le transfert de "
 | 
			
		||||
                        + pretty_money(dest.quantity * 100 * $("#amount").val()) + " de votre note "
 | 
			
		||||
                        + " vers la note " + dest.name + " a été fait avec succès !", "success");
 | 
			
		||||
 | 
			
		||||
                    reset();
 | 
			
		||||
                }).fail(function (err) {
 | 
			
		||||
                    addMsg("Le transfert de "
 | 
			
		||||
                        + pretty_money(dest.quantity * 100 * $("#amount").val()) + " de votre note "
 | 
			
		||||
                        + " vers la note " + dest.name + " a échoué : " + err.responseText, "danger");
 | 
			
		||||
                }).fail(function () {
 | 
			
		||||
                    $.post("/api/note/transaction/transaction/",
 | 
			
		||||
                    {
 | 
			
		||||
                        "csrfmiddlewaretoken": CSRF_TOKEN,
 | 
			
		||||
                        "quantity": dest.quantity,
 | 
			
		||||
                        "amount": 100 * $("#amount").val(),
 | 
			
		||||
                        "reason": $("#reason").val(),
 | 
			
		||||
                        "valid": false,
 | 
			
		||||
                        "invalidity_reason": "Solde insuffisant",
 | 
			
		||||
                        "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
 | 
			
		||||
                        "resourcetype": "Transaction",
 | 
			
		||||
                        "source": user_id,
 | 
			
		||||
                        "destination": dest.id,
 | 
			
		||||
                        "destination_alias": dest.name
 | 
			
		||||
                    }).done(function () {
 | 
			
		||||
                        addMsg("Le transfert de "
 | 
			
		||||
                            + pretty_money(dest.quantity * 100 * $("#amount").val()) + " de votre note "
 | 
			
		||||
                            + " vers la note " + dest.name + " a échoué : Solde insuffisant", "danger");
 | 
			
		||||
 | 
			
		||||
                reset();
 | 
			
		||||
                        reset();
 | 
			
		||||
                    }).fail(function (err) {
 | 
			
		||||
                        addMsg("Le transfert de "
 | 
			
		||||
                            + pretty_money(dest.quantity * 100 * $("#amount").val()) + " de votre note "
 | 
			
		||||
                            + " vers la note " + dest.name + " a échoué : " + err.responseText, "danger");
 | 
			
		||||
 | 
			
		||||
                    reset();
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
@@ -112,19 +134,43 @@ $("#transfer").click(function() {
 | 
			
		||||
                        "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
 | 
			
		||||
                        "resourcetype": "Transaction",
 | 
			
		||||
                        "source": source.id,
 | 
			
		||||
                        "destination": dest.id
 | 
			
		||||
                    }, function () {
 | 
			
		||||
                        "source_alias": source.name,
 | 
			
		||||
                        "destination": dest.id,
 | 
			
		||||
                        "destination_alias": dest.name
 | 
			
		||||
                    }).done(function () {
 | 
			
		||||
                        addMsg("Le transfert de "
 | 
			
		||||
                            + pretty_money(source.quantity * dest.quantity * 100 * $("#amount").val()) + " de la note " + source.name
 | 
			
		||||
                            + " vers la note " + dest.name + " a été fait avec succès !", "success");
 | 
			
		||||
 | 
			
		||||
                        reset();
 | 
			
		||||
                    }).fail(function (err) {
 | 
			
		||||
                        addMsg("Le transfert de "
 | 
			
		||||
                            + pretty_money(source.quantity * dest.quantity * 100 * $("#amount").val()) + " de la note " + source.name
 | 
			
		||||
                            + " vers la note " + dest.name + " a échoué : " + err.responseText, "danger");
 | 
			
		||||
                        $.post("/api/note/transaction/transaction/",
 | 
			
		||||
                        {
 | 
			
		||||
                            "csrfmiddlewaretoken": CSRF_TOKEN,
 | 
			
		||||
                            "quantity": source.quantity * dest.quantity,
 | 
			
		||||
                            "amount": 100 * $("#amount").val(),
 | 
			
		||||
                            "reason": $("#reason").val(),
 | 
			
		||||
                            "valid": false,
 | 
			
		||||
                            "invalidity_reason": "Solde insuffisant",
 | 
			
		||||
                            "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
 | 
			
		||||
                            "resourcetype": "Transaction",
 | 
			
		||||
                            "source": source.id,
 | 
			
		||||
                            "source_alias": source.name,
 | 
			
		||||
                            "destination": dest.id,
 | 
			
		||||
                            "destination_alias": dest.name
 | 
			
		||||
                        }).done(function () {
 | 
			
		||||
                            addMsg("Le transfert de "
 | 
			
		||||
                                + pretty_money(source.quantity * dest.quantity * 100 * $("#amount").val()) + " de la note " + source.name
 | 
			
		||||
                                + " vers la note " + dest.name + " a échoué : Solde insuffisant", "danger");
 | 
			
		||||
 | 
			
		||||
                        reset();
 | 
			
		||||
                            reset();
 | 
			
		||||
                        }).fail(function (err) {
 | 
			
		||||
                            addMsg("Le transfert de "
 | 
			
		||||
                                + pretty_money(source.quantity * dest.quantity * 100 * $("#amount").val()) + " de la note " + source.name
 | 
			
		||||
                                + " vers la note " + dest.name + " a échoué : " + err.responseText, "danger");
 | 
			
		||||
 | 
			
		||||
                            reset();
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
@@ -157,15 +203,17 @@ $("#transfer").click(function() {
 | 
			
		||||
                "polymorphic_ctype": SPECIAL_TRANSFER_POLYMORPHIC_CTYPE,
 | 
			
		||||
                "resourcetype": "SpecialTransaction",
 | 
			
		||||
                "source": source,
 | 
			
		||||
                "source_alias": source.name,
 | 
			
		||||
                "destination": dest,
 | 
			
		||||
                "destination_alias": dest.name,
 | 
			
		||||
                "last_name": $("#last_name").val(),
 | 
			
		||||
                "first_name": $("#first_name").val(),
 | 
			
		||||
                "bank": $("#bank").val()
 | 
			
		||||
            }, function () {
 | 
			
		||||
            }).done(function () {
 | 
			
		||||
                addMsg("Le crédit/retrait a bien été effectué !", "success");
 | 
			
		||||
                reset();
 | 
			
		||||
            }).fail(function (err) {
 | 
			
		||||
                addMsg("Le crédit/transfert a échoué : " + err.responseText, "danger");
 | 
			
		||||
                addMsg("Le crédit/retrait a échoué : " + err.responseText, "danger");
 | 
			
		||||
                reset();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -79,9 +79,11 @@ SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
                        <a class="nav-link" href="{% url 'note:consos' %}"><i class="fa fa-coffee"></i> {% trans 'Consumptions' %}</a>
 | 
			
		||||
                    </li>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
                {% if "note.transaction"|not_empty_model_list %}
 | 
			
		||||
                    <li class="nav-item active">
 | 
			
		||||
                        <a class="nav-link" href="{% url 'note:transfer' %}"><i class="fa fa-exchange"></i>{% trans 'Transfer' %} </a>
 | 
			
		||||
                    </li>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
                {% if "member.club"|not_empty_model_list %}
 | 
			
		||||
                    <li class="nav-item active">
 | 
			
		||||
                        <a class="nav-link" href="{% url 'member:club_list' %}"><i class="fa fa-users"></i> {% trans 'Clubs' %}</a>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,11 @@
 | 
			
		||||
{% extends "base.html" %}
 | 
			
		||||
{% extends "member/noteowner_detail.html" %}
 | 
			
		||||
{% load crispy_forms_tags %}
 | 
			
		||||
{% load static %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
 | 
			
		||||
{% block profile_info %}
 | 
			
		||||
{% include "member/club_info.html" %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
{% block profile_content %}
 | 
			
		||||
 | 
			
		||||
<form method="post" action="">
 | 
			
		||||
    {% csrf_token %}
 | 
			
		||||
@@ -10,9 +14,9 @@
 | 
			
		||||
        <input type="submit" name="submit" value="Add Members" class="btn btn-primary" id="submit-save">
 | 
			
		||||
    </div>
 | 
			
		||||
</form>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
<!-- Include formset plugin - including jQuery dependency -->
 | 
			
		||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
 | 
			
		||||
{% block extrajavascript %}
 | 
			
		||||
<script src="{% static 'js/dynamic-formset.js' %}"></script>
 | 
			
		||||
<script>
 | 
			
		||||
    $('.formset-row').formset({
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								templates/member/alias_update.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								templates/member/alias_update.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
{% load django_tables2 crispy_forms_tags i18n %}
 | 
			
		||||
<div class="d-flex justify-content-center">
 | 
			
		||||
    <input id="alias_input" type="text" value=""/>
 | 
			
		||||
    <button id="alias_submit" class="btn btn-primary mx-2" onclick="create_alias( {{ object.note.pk }} )" type="submit">
 | 
			
		||||
        {% trans "Add alias" %}
 | 
			
		||||
    </button>
 | 
			
		||||
</div>
 | 
			
		||||
<div class="card bg-light shadow">
 | 
			
		||||
    <div class="card-body">
 | 
			
		||||
        {% render_table aliases %}
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										10
									
								
								templates/member/club_alias.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								templates/member/club_alias.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
{% extends "member/club_detail.html" %}
 | 
			
		||||
{% load i18n static pretty_money django_tables2 crispy_forms_tags %}
 | 
			
		||||
 | 
			
		||||
{% block profile_content %}
 | 
			
		||||
{% include "member/alias_update.html" %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block extrajavascript %}
 | 
			
		||||
<script src="/static/js/alias.js"></script>
 | 
			
		||||
{% endblock%}
 | 
			
		||||
@@ -1,5 +1,8 @@
 | 
			
		||||
{% load i18n static pretty_money %}
 | 
			
		||||
<div class="card bg-light shadow">
 | 
			
		||||
    <div class="card-header text-center">
 | 
			
		||||
        <h4> Club {{ club.name }} </h4>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="card-top text-center">
 | 
			
		||||
        <a  href="{% url 'member:club_update_pic' club.pk  %}">
 | 
			
		||||
            <img src="{{ club.note.display_image.url }}" class="img-thumbnail mt-2" >
 | 
			
		||||
@@ -10,6 +13,9 @@
 | 
			
		||||
            <dt class="col-xl-6">{% trans 'name'|capfirst %}</dt>
 | 
			
		||||
            <dd class="col-xl-6">{{ club.name}}</dd>
 | 
			
		||||
 | 
			
		||||
            <dt class="col-xl-6"><a href="{% url 'member:club_detail' club.parent_club.pk %}">{% trans 'Club Parent'|capfirst %}</a></dt>
 | 
			
		||||
            <dd class="col-xl-6"> {{ club.parent_club.name}}</dd>
 | 
			
		||||
 | 
			
		||||
            <dt class="col-xl-6">{% trans 'membership start'|capfirst %}</dt>
 | 
			
		||||
            <dd class="col-xl-6">{{ club.membership_start }}</dd>
 | 
			
		||||
 | 
			
		||||
@@ -22,11 +28,19 @@
 | 
			
		||||
            <dt class="col-xl-6">{% trans 'membership fee'|capfirst %}</dt>
 | 
			
		||||
            <dd class="col-xl-6">{{ club.membership_fee|pretty_money }}</dd>
 | 
			
		||||
            
 | 
			
		||||
            <dt class="col-xl-6"><a href="{% url 'member:user_alias' club.pk %}">{% trans 'aliases'|capfirst %}</a></dt>
 | 
			
		||||
            <dt class="col-xl-6"><a href="{% url 'member:club_alias' club.pk %}">{% trans 'aliases'|capfirst %}</a></dt>
 | 
			
		||||
            <dd class="col-xl-6 text-truncate">{{ object.note.alias_set.all|join:", " }}</dd>
 | 
			
		||||
 | 
			
		||||
            <dt class="col-xl-3">{% trans 'email'|capfirst %}</dt>
 | 
			
		||||
            <dd class="col-xl-9"><a href="mailto:{{ club.email }}">{{ club.email}}</a></dd>
 | 
			
		||||
        </dl>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="card-footer text-center">
 | 
			
		||||
        <a class="btn btn-primary btn-sm my-1" href="{% url 'member:club_add_member' pk=club.pk %}"> {% trans "Add member" %}</a>
 | 
			
		||||
        <a class="btn btn-primary btn-sm my-1" href="{% url 'member:club_update' pk=club.pk %}"> {% trans "Edit" %}</a>
 | 
			
		||||
        <a class="btn btn-primary btn-sm my-1" href="{% url 'member:club_add_member' pk=club.pk %}"> {% trans "Add roles" %}</a>
 | 
			
		||||
        {% url 'member:club_detail' club.pk as club_detail_url %}
 | 
			
		||||
        {%if request.get_full_path != club_detail_url %}
 | 
			
		||||
        <a class="btn btn-primary btn-sm my-1" href="{{ user_profile_url }}">{% trans 'View Profile' %}</a>
 | 
			
		||||
        {% endif %}    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,6 @@
 | 
			
		||||
{% extends "member/club_detail.html" %}
 | 
			
		||||
{% load i18n static pretty_money django_tables2 crispy_forms_tags %}
 | 
			
		||||
 | 
			
		||||
{% block profile_info %}
 | 
			
		||||
{% include "member/club_info.html" %}
 | 
			
		||||
{% endblock%}
 | 
			
		||||
 | 
			
		||||
{% block profile_content%}
 | 
			
		||||
{% include "member/picture_update.html" %}
 | 
			
		||||
{% endblock%}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,18 +2,9 @@
 | 
			
		||||
{% load i18n static pretty_money django_tables2 crispy_forms_tags %}
 | 
			
		||||
 | 
			
		||||
{% block profile_content %}
 | 
			
		||||
        <div class="d-flex justify-content-center">
 | 
			
		||||
            <form class=" text-center form my-2" action="" method="post">
 | 
			
		||||
                {% csrf_token %}
 | 
			
		||||
                {{ form |crispy }}
 | 
			
		||||
                <button class="btn btn-primary mx-2" type="submit">
 | 
			
		||||
                    {% trans "Add alias" %}
 | 
			
		||||
                </button>
 | 
			
		||||
            </form>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card bg-light shadow">
 | 
			
		||||
            <div class="card-body">
 | 
			
		||||
                {% render_table aliases %}
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
{% include "member/alias_update.html"%}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block extrajavascript %}
 | 
			
		||||
<script src="/static/js/alias.js"></script>
 | 
			
		||||
{% endblock%}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,9 @@
 | 
			
		||||
{% load i18n static pretty_money %}
 | 
			
		||||
 | 
			
		||||
<div class="card bg-light shadow">
 | 
			
		||||
    <div class="card-header text-center" >
 | 
			
		||||
        <h4> {% trans "Account #" %}  {{ object.pk }}</h4>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="card-top text-center">
 | 
			
		||||
        <a  href="{% url 'member:user_update_pic' object.pk  %}">
 | 
			
		||||
            <img src="{{ object.note.display_image.url }}" class="img-thumbnail mt-2" >
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,6 @@
 | 
			
		||||
{% extends "member/noteowner_detail.html" %}
 | 
			
		||||
{% extends "member/profile_detail.html" %}
 | 
			
		||||
{% load i18n static pretty_money django_tables2 crispy_forms_tags %}
 | 
			
		||||
 | 
			
		||||
{% block profile_info %}
 | 
			
		||||
{% include "member/profile_info.html" %}
 | 
			
		||||
{% endblock%}
 | 
			
		||||
 | 
			
		||||
{% block profile_content%}
 | 
			
		||||
{% include "member/picture_update.html" %}
 | 
			
		||||
{% endblock%}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
        </h4>
 | 
			
		||||
        <input class="form-control mx-auto w-25" type="text" onkeyup="search_field_moved();return(false);" id="search_field"/>
 | 
			
		||||
        <hr>
 | 
			
		||||
        <a class="btn btn-primary text-center my-4" href="{% url 'note:template_create' %}">Créer un bouton</a>
 | 
			
		||||
        <a class="btn btn-primary text-center my-1" href="{% url 'note:template_create' %}">{% trans "New button" %}</a>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
<div class="row justify-content-center">   
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user