From d8949a993a30640ac8799a9eb9928f2b907ec6a8 Mon Sep 17 00:00:00 2001 From: Pierre-antoine Comby Date: Sat, 28 Mar 2020 17:42:29 +0100 Subject: [PATCH 01/32] get alias and note infos together --- apps/note/api/serializers.py | 14 ++++++++++++++ apps/note/api/urls.py | 5 +++-- apps/note/api/views.py | 27 +++++++++++++++++++++++++-- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/apps/note/api/serializers.py b/apps/note/api/serializers.py index a51b4263..27ff6d65 100644 --- a/apps/note/api/serializers.py +++ b/apps/note/api/serializers.py @@ -92,6 +92,20 @@ class NotePolymorphicSerializer(PolymorphicSerializer): class Meta: model = Note +class ConsumerSerializer(serializers.ModelSerializer): + """ + REST API Nested Serializer for Consumers. + return Alias, and the note Associated to it in + """ + note = NotePolymorphicSerializer() + class Meta: + model = Alias + fields = '__all__' + + @staticmethod + def setup_eager_loading(queryset): + queryset = queryset.select_related('note') + class TemplateCategorySerializer(serializers.ModelSerializer): """ diff --git a/apps/note/api/urls.py b/apps/note/api/urls.py index 796a397f..57909080 100644 --- a/apps/note/api/urls.py +++ b/apps/note/api/urls.py @@ -1,7 +1,7 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later -from .views import NotePolymorphicViewSet, AliasViewSet, \ +from .views import NotePolymorphicViewSet, AliasViewSet, ConsumerViewSet, \ TemplateCategoryViewSet, TransactionViewSet, TransactionTemplateViewSet @@ -11,7 +11,8 @@ def register_note_urls(router, path): """ router.register(path + '/note', NotePolymorphicViewSet) router.register(path + '/alias', AliasViewSet) - + router.register(path + '/consumer', ConsumerViewSet) + router.register(path + '/transaction/category', TemplateCategoryViewSet) router.register(path + '/transaction/transaction', TransactionViewSet) router.register(path + '/transaction/template', TransactionTemplateViewSet) diff --git a/apps/note/api/views.py b/apps/note/api/views.py index f230a646..af02dc8b 100644 --- a/apps/note/api/views.py +++ b/apps/note/api/views.py @@ -6,8 +6,8 @@ from django_filters.rest_framework import DjangoFilterBackend from rest_framework.filters import OrderingFilter, SearchFilter from api.viewsets import ReadProtectedModelViewSet, ReadOnlyProtectedModelViewSet -from .serializers import NotePolymorphicSerializer, AliasSerializer, TemplateCategorySerializer, \ - TransactionTemplateSerializer, TransactionPolymorphicSerializer +from .serializers import NotePolymorphicSerializer, AliasSerializer, ConsumerSerializer,\ + TemplateCategorySerializer, TransactionTemplateSerializer, TransactionPolymorphicSerializer from ..models.notes import Note, Alias from ..models.transactions import TransactionTemplate, Transaction, TemplateCategory @@ -68,6 +68,29 @@ class AliasViewSet(ReadProtectedModelViewSet): return queryset +class ConsumerViewSet(ReadOnlyProtectedModelViewSet): + queryset = Alias.objects.all() + serializer_class = ConsumerSerializer + filter_backends = [SearchFilter, OrderingFilter] + search_fields = ['$normalized_name', '$name', '$note__polymorphic_ctype__model', ] + ordering_fields = ['name', 'normalized_name'] + + def get_queryset(self): + """ + Parse query and apply filters. + :return: The filtered set of requested aliases + """ + + queryset = super().get_queryset() + + alias = self.request.query_params.get("alias", ".*") + queryset = queryset.filter( + Q(name__regex="^" + alias) + | Q(normalized_name__regex="^" + Alias.normalize(alias)) + | Q(normalized_name__regex="^" + alias.lower())) + + return queryset + class TemplateCategoryViewSet(ReadProtectedModelViewSet): """ From f3656f367c2fc8ec8a17983099af7423e8a00033 Mon Sep 17 00:00:00 2001 From: Pierre-antoine Comby Date: Sat, 28 Mar 2020 17:44:03 +0100 Subject: [PATCH 02/32] default picture is 200x200 --- media/pic/default.png | Bin 9259 -> 4054 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/media/pic/default.png b/media/pic/default.png index f933bc341619178775520150d514effb2339b10a..41a31a1cf5eddf31e98a7e6cd06b4c45f2faee92 100644 GIT binary patch literal 4054 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 IM6N<$f;wYbJOBUy literal 9259 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 Date: Sat, 28 Mar 2020 17:44:22 +0100 Subject: [PATCH 03/32] color codes from note balances --- static/js/base.js | 131 +++++++++++++++++++-------------- templates/note/conso_form.html | 16 ++-- 2 files changed, 87 insertions(+), 60 deletions(-) diff --git a/static/js/base.js b/static/js/base.js index f7085850..61372c76 100644 --- a/static/js/base.js +++ b/static/js/base.js @@ -48,10 +48,27 @@ function getMatchedNotes(pattern, fun) { /** * Generate a
  • entry with a given id and text */ -function li(id, text) { - return "
  • " + text + "
  • \n"; } +/** + * Return style to apply according to the balance of the note + * @param balance The balance of the note. + */ +function displayStyle(balance){ + if (balance < -5000){ + return " text-danger bg-dark" + } + else if(balance <-1000){ + return " text-danger" + } + else if(balance < 0){ + return "text-warning" + } + return "" +} + /** * Render note name and picture @@ -62,24 +79,28 @@ function li(id, text) { */ function displayNote(note, alias, user_note_field=null, profile_pic_field=null) { if (!note.display_image) { - note.display_image = 'https://nk20.ynerant.fr/media/pic/default.png'; - $.getJSON("/api/note/note/" + note.id + "/?format=json", function(new_note) { - note.display_image = new_note.display_image.replace("http:", "https:"); - note.name = new_note.name; - note.balance = new_note.balance; - - displayNote(note, alias, user_note_field, profile_pic_field); - }); - return; + note.display_image = '/media/pic/default.png'; } let img = note.display_image; if (alias !== note.name) alias += " (aka. " + note.name + ")"; if (user_note_field !== null) + + $("#" + user_note_field).addClass(displayStyle(note.balance)); $("#" + user_note_field).text(alias + (note.balance == null ? "" : (" : " + pretty_money(note.balance)))); - if (profile_pic_field != null) + if (profile_pic_field != null){ $("#" + profile_pic_field).attr('src', img); + $("#" + profile_pic_field).click(function(){ + console.log(note); + if(note.resourcetype == "NoteUser"){ + document.location.href = "/accounts/user/" + note.user; + } + else if(note.resourcetype == "NoteClub"){ + document.location.href = "/accounts/club/" + note.club; + } + }); + } } /** @@ -153,8 +174,11 @@ function autoCompleteNote(field_id, alias_matched_id, note_list_id, notes, notes // When the user type "Enter", the first alias is clicked field.keypress(function(event) { - if (event.originalEvent.charCode === 13) - $("#" + alias_matched_id + " li").first().trigger("click"); + if (event.originalEvent.charCode === 13 && notes.length > 0) { + let li_obj = $("#" + alias_matched_id + " li").first(); + displayNote(notes[0], li_obj.text(), user_note_field, profile_pic_field); + li_obj.trigger("click"); + } }); // When the user type something, the matched aliases are refreshed @@ -164,51 +188,46 @@ function autoCompleteNote(field_id, alias_matched_id, note_list_id, notes, notes let pattern = field.val(); // If the pattern is not modified, we don't query the API - if (pattern === old_pattern || pattern === "") + if (pattern === old_pattern) return; - old_pattern = pattern; - - // Clear old matched notes notes.length = 0; let aliases_matched_obj = $("#" + alias_matched_id); let aliases_matched_html = ""; - - // Get matched notes with the given pattern - getMatchedNotes(pattern, function(aliases) { + // get matched Alias with note associated + if(pattern == ""){ + aliases_matched_obj = $("#" + alias_matched_id); + aliases_matched_html = ""; + aliases_matched_obj.html("") + notes.length = 0; + return; + } + + $.getJSON("/api/note/consumer/?format=json&alias=" + + pattern + + "&search=user|club&ordering=normalized_name", + function(consumers){ // The response arrived too late, we stop the request if (pattern !== $("#" + field_id).val()) return; - - aliases.results.forEach(function (alias) { - let note = alias.note; - note = { - id: note, - name: alias.name, - alias: alias, - balance: null - }; - aliases_matched_html += li(alias_prefix + "_" + alias.id, alias.name); + consumers.results.forEach(function (consumer){ + let note = consumer.note; + extra_css = displayStyle(note.balance); + aliases_matched_html += li(alias_prefix + '_' + consumer.id, + consumer.name, + extra_css); notes.push(note); }); - - // Display the list of matched aliases aliases_matched_obj.html(aliases_matched_html); - - notes.forEach(function (note) { - let alias = note.alias; - let alias_obj = $("#" + alias_prefix + "_" + alias.id); - // When an alias is hovered, the profile picture and the balance are displayed at the right place - alias_obj.hover(function () { - displayNote(note, alias.name, user_note_field, profile_pic_field); + consumers.results.forEach(function(consumer){ + let note = consumer.note; + let consumer_obj = $("#" + alias_prefix+ "_" + consumer.id); + consumer_obj.hover(function(){ + displayNote(consumer.note, consumer.name, user_note_field,profile_pic_field) }); - - // When the user click on an alias, the associated note is added to the emitters - alias_obj.click(function () { - field.val(""); - old_pattern = ""; - // If the note is already an emitter, we increase the quantity + consumer_obj.click(function(){ + field.val(""); old_pattern = ""; // reset input field var disp = null; notes_display.forEach(function (d) { // We compare the note ids @@ -220,8 +239,8 @@ function autoCompleteNote(field_id, alias_matched_id, note_list_id, notes, notes // In the other case, we add a new emitter if (disp == null) { disp = { - name: alias.name, - id: note.id, + name: consumer.name, + id: consumer.id, note: note, quantity: 1 }; @@ -236,8 +255,11 @@ function autoCompleteNote(field_id, alias_matched_id, note_list_id, notes, notes let note_list = $("#" + note_list_id); let html = ""; notes_display.forEach(function (disp) { - html += li(note_prefix + "_" + disp.id, disp.name - + "" + disp.quantity + ""); + html += li(note_prefix + "_" + disp.id, + disp.name + + "" + + disp.quantity + "", + displayStyle(disp.note.balance)); }); // Emitters are displayed @@ -254,11 +276,12 @@ function autoCompleteNote(field_id, alias_matched_id, note_list_id, notes, notes line_obj.click(removeNote(disp, note_prefix, notes_display, note_list_id, user_note_field, profile_pic_field)); }); - }); + }) }); - }); - }); -} + + });// end getJSON alias + }); +}// end function autocomplete // When a validate button is clicked, we switch the validation status function de_validate(id, validated) { diff --git a/templates/note/conso_form.html b/templates/note/conso_form.html index b108a96f..36659849 100644 --- a/templates/note/conso_form.html +++ b/templates/note/conso_form.html @@ -11,9 +11,10 @@
    {# User details column #}
    -
    +
    + id="profile_pic" alt="" + class="img-thumbnail">
    @@ -25,14 +26,17 @@

    - {% trans "Select emitters" %} + {% trans "Consum" %}

    +
    -
    - -
      +
    +
    From aaf49c9b99a9275127873de5fb76ac56f9d4928e Mon Sep 17 00:00:00 2001 From: Pierre-antoine Comby Date: Sat, 28 Mar 2020 21:30:55 +0100 Subject: [PATCH 04/32] balance on a second line --- static/js/base.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/static/js/base.js b/static/js/base.js index 61372c76..86e090f9 100644 --- a/static/js/base.js +++ b/static/js/base.js @@ -81,14 +81,13 @@ function displayNote(note, alias, user_note_field=null, profile_pic_field=null) if (!note.display_image) { note.display_image = '/media/pic/default.png'; } - let img = note.display_image; if (alias !== note.name) alias += " (aka. " + note.name + ")"; if (user_note_field !== null) $("#" + user_note_field).addClass(displayStyle(note.balance)); - $("#" + user_note_field).text(alias + (note.balance == null ? "" : (" : " + pretty_money(note.balance)))); + $("#" + user_note_field).text(alias + (note.balance == null ? "" : (":\n" + pretty_money(note.balance)))); if (profile_pic_field != null){ $("#" + profile_pic_field).attr('src', img); $("#" + profile_pic_field).click(function(){ From 935ebf291afd54e31dbc325c699c354c846c7c5a Mon Sep 17 00:00:00 2001 From: Pierre-antoine Comby Date: Sat, 28 Mar 2020 21:31:22 +0100 Subject: [PATCH 05/32] use note id , not alias id --- static/js/consos.js | 2 +- static/js/transfer.js | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/static/js/consos.js b/static/js/consos.js index 20859933..9450febc 100644 --- a/static/js/consos.js +++ b/static/js/consos.js @@ -167,7 +167,7 @@ function reset() { function consumeAll() { notes_display.forEach(function(note_display) { buttons.forEach(function(button) { - consume(note_display.id, note_display.name, button.dest, button.quantity * note_display.quantity, button.amount, + consume(note_display.note.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); }); }); diff --git a/static/js/transfer.js b/static/js/transfer.js index cf62e453..5b673acb 100644 --- a/static/js/transfer.js +++ b/static/js/transfer.js @@ -83,7 +83,7 @@ $("#transfer").click(function() { "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE, "resourcetype": "Transaction", "source": user_id, - "destination": dest.id, + "destination": dest.note.id, "destination_alias": dest.name }).done(function () { addMsg("Le transfert de " @@ -91,7 +91,7 @@ $("#transfer").click(function() { + " vers la note " + dest.name + " a été fait avec succès !", "success"); reset(); - }).fail(function () { + }).fail(function () { // do it again but valid = false $.post("/api/note/transaction/transaction/", { "csrfmiddlewaretoken": CSRF_TOKEN, @@ -103,7 +103,7 @@ $("#transfer").click(function() { "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE, "resourcetype": "Transaction", "source": user_id, - "destination": dest.id, + "destination": dest.note.id, "destination_alias": dest.name }).done(function () { addMsg("Le transfert de " @@ -133,9 +133,9 @@ $("#transfer").click(function() { "valid": true, "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE, "resourcetype": "Transaction", - "source": source.id, + "source": source.note.id, "source_alias": source.name, - "destination": dest.id, + "destination": dest.note.id, "destination_alias": dest.name }).done(function () { addMsg("Le transfert de " @@ -143,7 +143,7 @@ $("#transfer").click(function() { + " vers la note " + dest.name + " a été fait avec succès !", "success"); reset(); - }).fail(function (err) { + }).fail(function (err) { // do it again but valid = false $.post("/api/note/transaction/transaction/", { "csrfmiddlewaretoken": CSRF_TOKEN, @@ -154,9 +154,9 @@ $("#transfer").click(function() { "invalidity_reason": "Solde insuffisant", "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE, "resourcetype": "Transaction", - "source": source.id, + "source": source.note.id, "source_alias": source.name, - "destination": dest.id, + "destination": dest.note.id, "destination_alias": dest.name }).done(function () { addMsg("Le transfert de " @@ -176,7 +176,7 @@ $("#transfer").click(function() { }); } else if ($("#type_credit").is(':checked') || $("#type_debit").is(':checked')) { let special_note = $("#credit_type").val(); - let user_note = dests_notes_display[0].id; + let user_note = dests_notes_display[0].note.id; let given_reason = $("#reason").val(); let source, dest, reason; if ($("#type_credit").is(':checked')) { @@ -217,4 +217,4 @@ $("#transfer").click(function() { reset(); }); } -}); \ No newline at end of file +}); From 751147f254e07c54d9a9e32da001d1ecb74f61fa Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 10 Apr 2020 00:02:22 +0200 Subject: [PATCH 06/32] Don't display a note that we can't see, fix CI, fix distinct fields on PostgresSQL DB --- apps/activity/models.py | 4 ++-- apps/activity/views.py | 19 +++++++++++++------ apps/note/api/serializers.py | 18 ++++++++++++------ apps/note/api/urls.py | 2 +- apps/note/api/views.py | 3 ++- apps/permission/backends.py | 20 ++++++++++++++------ apps/treasury/views.py | 6 +++--- static/js/base.js | 2 +- 8 files changed, 48 insertions(+), 26 deletions(-) diff --git a/apps/activity/models.py b/apps/activity/models.py index 29f04b39..cab229c4 100644 --- a/apps/activity/models.py +++ b/apps/activity/models.py @@ -139,7 +139,7 @@ class Entry(models.Model): verbose_name = _("entry") verbose_name_plural = _("entries") - def save(self, *args,**kwargs): + def save(self, *args, **kwargs): qs = Entry.objects.filter(~Q(pk=self.pk), activity=self.activity, note=self.note, guest=self.guest) if qs.exists(): @@ -153,7 +153,7 @@ class Entry(models.Model): if self.note.balance < 0: raise ValidationError(_("The balance is negative.")) - ret = super().save(*args,**kwargs) + ret = super().save(*args, **kwargs) if insert and self.guest: GuestTransaction.objects.create( diff --git a/apps/activity/views.py b/apps/activity/views.py index 14746929..c0ae6a4e 100644 --- a/apps/activity/views.py +++ b/apps/activity/views.py @@ -3,6 +3,7 @@ from datetime import datetime, timezone +from django.conf import settings from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.contenttypes.models import ContentType from django.db.models import F, Q @@ -45,8 +46,8 @@ class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView context['title'] = _("Activities") upcoming_activities = Activity.objects.filter(date_end__gt=datetime.now()) - context['upcoming'] = ActivityTable(data=upcoming_activities - .filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view"))) + context['upcoming'] = ActivityTable(data=upcoming_activities.filter( + PermissionBackend.filter_queryset(self.request.user, Activity, "view"))) return context @@ -138,8 +139,14 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView): | Q(note__noteuser__user__last_name__regex=pattern) | Q(name__regex=pattern) | Q(normalized_name__regex=Alias.normalize(pattern)))) \ - .filter(PermissionBackend.filter_queryset(self.request.user, Alias, "view"))\ - .distinct()[:20] + .filter(PermissionBackend.filter_queryset(self.request.user, Alias, "view")) + if settings.DATABASES[note_qs.db]["ENGINE"] == 'django.db.backends.postgresql_psycopg2': + note_qs = note_qs.distinct('note__pk')[:20] + else: + # SQLite doesn't support distinct fields. For compatibility reason (in dev mode), the note list will only + # have distinct aliases rather than distinct notes with a SQLite DB, but it can fill the result page. + # In production mode, please use PostgreSQL. + note_qs = note_qs.distinct()[:20] for note in note_qs: note.type = "Adhérent" note.activity = activity @@ -153,9 +160,9 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView): context["title"] = _('Entry for activity "{}"').format(activity.name) context["noteuser_ctype"] = ContentType.objects.get_for_model(NoteUser).pk context["notespecial_ctype"] = ContentType.objects.get_for_model(NoteSpecial).pk - + context["activities_open"] = Activity.objects.filter(open=True).filter( PermissionBackend.filter_queryset(self.request.user, Activity, "view")).filter( PermissionBackend.filter_queryset(self.request.user, Activity, "change")).all() - return context \ No newline at end of file + return context diff --git a/apps/note/api/serializers.py b/apps/note/api/serializers.py index 7005ce16..ce2ed97e 100644 --- a/apps/note/api/serializers.py +++ b/apps/note/api/serializers.py @@ -3,6 +3,8 @@ from rest_framework import serializers from rest_polymorphic.serializers import PolymorphicSerializer +from note_kfet.middlewares import get_current_authenticated_user +from permission.backends import PermissionBackend from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias from ..models.transactions import TransactionTemplate, Transaction, MembershipTransaction, TemplateCategory, \ @@ -96,20 +98,24 @@ class NotePolymorphicSerializer(PolymorphicSerializer): class Meta: model = Note + class ConsumerSerializer(serializers.ModelSerializer): """ REST API Nested Serializer for Consumers. - return Alias, and the note Associated to it in + return Alias, and the note Associated to it in """ - note = NotePolymorphicSerializer() + note = serializers.SerializerMethodField() + class Meta: model = Alias fields = '__all__' - @staticmethod - def setup_eager_loading(queryset): - queryset = queryset.select_related('note') - + def get_note(self, obj): + if PermissionBackend.check_perm(get_current_authenticated_user(), "note.view_note", obj.note): + print(obj.pk) + return NotePolymorphicSerializer().to_representation(obj.note) + return dict(id=obj.id) + class TemplateCategorySerializer(serializers.ModelSerializer): """ diff --git a/apps/note/api/urls.py b/apps/note/api/urls.py index 57909080..2f3fd1a9 100644 --- a/apps/note/api/urls.py +++ b/apps/note/api/urls.py @@ -12,7 +12,7 @@ def register_note_urls(router, path): router.register(path + '/note', NotePolymorphicViewSet) router.register(path + '/alias', AliasViewSet) router.register(path + '/consumer', ConsumerViewSet) - + router.register(path + '/transaction/category', TemplateCategoryViewSet) router.register(path + '/transaction/transaction', TransactionViewSet) router.register(path + '/transaction/template', TransactionTemplateViewSet) diff --git a/apps/note/api/views.py b/apps/note/api/views.py index 61ef19eb..d5ad8129 100644 --- a/apps/note/api/views.py +++ b/apps/note/api/views.py @@ -89,6 +89,7 @@ class AliasViewSet(ReadProtectedModelViewSet): return queryset + class ConsumerViewSet(ReadOnlyProtectedModelViewSet): queryset = Alias.objects.all() serializer_class = ConsumerSerializer @@ -111,7 +112,7 @@ class ConsumerViewSet(ReadOnlyProtectedModelViewSet): | Q(normalized_name__regex="^" + alias.lower())) return queryset - + class TemplateCategoryViewSet(ReadProtectedModelViewSet): """ diff --git a/apps/permission/backends.py b/apps/permission/backends.py index 04d93528..2407ea1b 100644 --- a/apps/permission/backends.py +++ b/apps/permission/backends.py @@ -8,6 +8,7 @@ from django.contrib.auth.models import User, AnonymousUser from django.contrib.contenttypes.models import ContentType from django.db.models import Q, F from note.models import Note, NoteUser, NoteClub, NoteSpecial +from note_kfet import settings from note_kfet.middlewares import get_current_session from member.models import Membership, Club @@ -36,14 +37,21 @@ class PermissionBackend(ModelBackend): # Unauthenticated users have no permissions return Permission.objects.none() - return Permission.objects.annotate(club=F("rolepermissions__role__membership__club")) \ + perms = Permission.objects.annotate(club=F("rolepermissions__role__membership__club")) \ .filter( rolepermissions__role__membership__user=user, rolepermissions__role__membership__date_start__lte=datetime.date.today(), rolepermissions__role__membership__date_end__gte=datetime.date.today(), type=t, - mask__rank__lte=get_current_session().get("permission_mask", 0), - ).distinct() + mask__rank__lte=get_current_session().get("permission_mask", 42), + ) + if settings.DATABASES[perms.db]["ENGINE"] == 'django.db.backends.postgresql_psycopg2': + # We want one permission per club, and per permission type. + # SQLite does not support this kind of filter, that's why we don't filter the permissions with this + # kind of DB. This only increases performances (we can check multiple times the same permission) + # but don't have any semantic influence. + perms = perms.distinct('club', 'pk') + return perms @staticmethod def permissions(user, model, type): @@ -95,7 +103,7 @@ class PermissionBackend(ModelBackend): # Anonymous users can't do anything return Q(pk=-1) - if user.is_superuser and get_current_session().get("permission_mask", 0) >= 42: + if user.is_superuser and get_current_session().get("permission_mask", 42) >= 42: # Superusers have all rights return Q() @@ -129,9 +137,9 @@ class PermissionBackend(ModelBackend): sess = get_current_session() if sess is not None and sess.session_key is None: - return Permission.objects.none() + return False - if user_obj.is_superuser and get_current_session().get("permission_mask", 0) >= 42: + if user_obj.is_superuser and get_current_session().get("permission_mask", 42) >= 42: return True if obj is None: diff --git a/apps/treasury/views.py b/apps/treasury/views.py index 7361d1d2..8d744443 100644 --- a/apps/treasury/views.py +++ b/apps/treasury/views.py @@ -203,9 +203,9 @@ class RemittanceCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context["table"] = RemittanceTable(data=Remittance.objects - .filter(PermissionBackend.filter_queryset(self.request.user, Remittance, "view")) - .all()) + context["table"] = RemittanceTable( + data=Remittance.objects.filter( + PermissionBackend.filter_queryset(self.request.user, Remittance, "view")).all()) context["special_transactions"] = SpecialTransactionTable(data=SpecialTransaction.objects.none()) return context diff --git a/static/js/base.js b/static/js/base.js index 179bdd3b..fc933794 100644 --- a/static/js/base.js +++ b/static/js/base.js @@ -119,7 +119,7 @@ function displayNote(note, alias, user_note_field=null, profile_pic_field=null) note.display_image = '/media/pic/default.png'; } let img = note.display_image; - if (alias !== note.name) + if (alias !== note.name && note.name) alias += " (aka. " + note.name + ")"; if (user_note_field !== null) From 6477590cd43af931b66f0d5e84193d90e7da08cf Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 10 Apr 2020 00:09:10 +0200 Subject: [PATCH 07/32] Fix devalidation --- apps/note/api/serializers.py | 4 ++++ apps/note/tables.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/note/api/serializers.py b/apps/note/api/serializers.py index ce2ed97e..70aecf44 100644 --- a/apps/note/api/serializers.py +++ b/apps/note/api/serializers.py @@ -111,6 +111,10 @@ class ConsumerSerializer(serializers.ModelSerializer): fields = '__all__' def get_note(self, obj): + """ + Display information about the associated note + """ + # If the user has no right to see the note, then we only display the note identifier if PermissionBackend.check_perm(get_current_authenticated_user(), "note.view_note", obj.note): print(obj.pk) return NotePolymorphicSerializer().to_representation(obj.note) diff --git a/apps/note/tables.py b/apps/note/tables.py index a38beb9a..8504121c 100644 --- a/apps/note/tables.py +++ b/apps/note/tables.py @@ -55,7 +55,7 @@ class HistoryTable(tables.Table): "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() + ')', + "onclick": lambda record: 'de_validate(' + str(record.id) + ', ' + str(record.valid).lower() + ')', "onmouseover": lambda record: '$("#invalidity_reason_' + str(record.id) + '").show();$("#invalidity_reason_' + str(record.id) + '").focus();', From 31205b9b5d3519de1666bcbe5ff2635dffa3e4a0 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 10 Apr 2020 02:42:21 +0200 Subject: [PATCH 08/32] Fix devalidation, clear class on note description --- static/js/base.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/static/js/base.js b/static/js/base.js index fc933794..43aa5ce3 100644 --- a/static/js/base.js +++ b/static/js/base.js @@ -123,6 +123,7 @@ function displayNote(note, alias, user_note_field=null, profile_pic_field=null) alias += " (aka. " + note.name + ")"; if (user_note_field !== null) + $("#" + user_note_field).removeAttr('class'); $("#" + user_note_field).addClass(displayStyle(note.balance)); $("#" + user_note_field).text(alias + (note.balance == null ? "" : (":\n" + pretty_money(note.balance)))); if (profile_pic_field != null){ @@ -321,10 +322,11 @@ 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) { + let invalidity_reason = $("#invalidity_reason_" + id).val(); $("#validate_" + id).html("⟳ ..."); // Perform a PATCH request to the API in order to update the transaction - // If the user has insuffisent rights, an error message will appear + // If the user has insufficient rights, an error message will appear $.ajax({ "url": "/api/note/transaction/transaction/" + id + "/", type: "PATCH", @@ -333,9 +335,9 @@ function de_validate(id, validated) { "X-CSRFTOKEN": CSRF_TOKEN }, data: { - resourcetype: "RecurrentTransaction", - valid: !validated, - invalidity_reason: invalidity_reason, + "resourcetype": "RecurrentTransaction", + "valid": !validated, + "invalidity_reason": invalidity_reason, }, success: function () { // Refresh jQuery objects From 658d40224200022122b263ca47c386f78aca3147 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 10 Apr 2020 02:56:56 +0200 Subject: [PATCH 09/32] Notes of users that don't have validated their email addresses are displayed with a different background --- apps/note/api/serializers.py | 7 + static/js/base.js | 253 ++++++++++++++++---------------- templates/member/user_list.html | 3 +- 3 files changed, 137 insertions(+), 126 deletions(-) diff --git a/apps/note/api/serializers.py b/apps/note/api/serializers.py index 70aecf44..c61ccd42 100644 --- a/apps/note/api/serializers.py +++ b/apps/note/api/serializers.py @@ -106,6 +106,8 @@ class ConsumerSerializer(serializers.ModelSerializer): """ note = serializers.SerializerMethodField() + email_confirmed = serializers.SerializerMethodField() + class Meta: model = Alias fields = '__all__' @@ -120,6 +122,11 @@ class ConsumerSerializer(serializers.ModelSerializer): return NotePolymorphicSerializer().to_representation(obj.note) return dict(id=obj.id) + def get_email_confirmed(self, obj): + if isinstance(obj.note, NoteUser): + return obj.note.user.profile.email_confirmed + return True + class TemplateCategorySerializer(serializers.ModelSerializer): """ diff --git a/static/js/base.js b/static/js/base.js index 43aa5ce3..56c23c85 100644 --- a/static/js/base.js +++ b/static/js/base.js @@ -21,7 +21,7 @@ function pretty_money(value) { * @param alert_type The type of the alert. Choices: info, success, warning, danger * @param timeout The delay (in millis) after that the message is auto-closed. If negative, then it is ignored. */ -function addMsg(msg, alert_type, timeout=-1) { +function addMsg(msg, alert_type, timeout = -1) { let msgDiv = $("#messages"); let html = msgDiv.html(); let id = Math.floor(10000 * Math.random() + 1); @@ -42,28 +42,28 @@ function addMsg(msg, alert_type, timeout=-1) { * @param errs_obj [{error_code:erro_message}] * @param timeout The delay (in millis) after that the message is auto-closed. If negative, then it is ignored. */ -function errMsg(errs_obj, timeout=-1) { +function errMsg(errs_obj, timeout = -1) { for (const err_msg of Object.values(errs_obj)) { - addMsg(err_msg,'danger', timeout); - } + addMsg(err_msg, 'danger', timeout); + } } var reloadWithTurbolinks = (function () { - var scrollPosition; + var scrollPosition; - function reload () { - scrollPosition = [window.scrollX, window.scrollY]; - Turbolinks.visit(window.location.toString(), { action: 'replace' }) - } - - document.addEventListener('turbolinks:load', function () { - if (scrollPosition) { - window.scrollTo.apply(window, scrollPosition); - scrollPosition = null + function reload() { + scrollPosition = [window.scrollX, window.scrollY]; + Turbolinks.visit(window.location.toString(), {action: 'replace'}) } - }); - return reload; + document.addEventListener('turbolinks:load', function () { + if (scrollPosition) { + window.scrollTo.apply(window, scrollPosition); + scrollPosition = null + } + }); + + return reload; })(); /** @@ -85,25 +85,27 @@ function getMatchedNotes(pattern, fun) { /** * Generate a
  • entry with a given id and text */ -function li(id, text,extra_css) { +function li(id, text, extra_css) { return "
  • " + text + "
  • \n"; + " id=\"" + id + "\">" + text + "\n"; } + /** - * Return style to apply according to the balance of the note - * @param balance The balance of the note. + * Return style to apply according to the balance of the note and the validation status of the email address + * @param note The concerned note. */ -function displayStyle(balance){ - if (balance < -5000){ - return " text-danger bg-dark" - } - else if(balance <-1000){ - return " text-danger" - } - else if(balance < 0){ - return "text-warning" - } - return "" +function displayStyle(note) { + let balance = note.balance; + var css = ""; + if (balance < -5000) + css += " text-danger bg-dark"; + else if (balance < -1000) + css += " text-danger"; + else if (balance < 0) + css += " text-warning"; + if (!note.email_confirmed) + css += " text-white bg-primary"; + return css; } @@ -114,29 +116,28 @@ function displayStyle(balance){ * @param user_note_field * @param profile_pic_field */ -function displayNote(note, alias, user_note_field=null, profile_pic_field=null) { +function displayNote(note, alias, user_note_field = null, profile_pic_field = null) { if (!note.display_image) { note.display_image = '/media/pic/default.png'; } let img = note.display_image; if (alias !== note.name && note.name) alias += " (aka. " + note.name + ")"; - if (user_note_field !== null) - + if (user_note_field !== null) { $("#" + user_note_field).removeAttr('class'); - $("#" + user_note_field).addClass(displayStyle(note.balance)); + $("#" + user_note_field).addClass(displayStyle(note)); $("#" + user_note_field).text(alias + (note.balance == null ? "" : (":\n" + pretty_money(note.balance)))); - if (profile_pic_field != null){ - $("#" + profile_pic_field).attr('src', img); - $("#" + profile_pic_field).click(function(){ - console.log(note); - if(note.resourcetype == "NoteUser"){ - document.location.href = "/accounts/user/" + note.user; - } - else if(note.resourcetype == "NoteClub"){ - document.location.href = "/accounts/club/" + note.club; - } - }); + if (profile_pic_field != null) { + $("#" + profile_pic_field).attr('src', img); + $("#" + profile_pic_field).click(function () { + console.log(note); + if (note.resourcetype === "NoteUser") { + document.location.href = "/accounts/user/" + note.user; + } else if (note.resourcetype === "NoteClub") { + document.location.href = "/accounts/club/" + note.club; + } + }); + } } } @@ -152,8 +153,8 @@ function displayNote(note, alias, user_note_field=null, profile_pic_field=null) * (useful in consumptions, put null if not used) * @returns an anonymous function to be compatible with jQuery events */ -function removeNote(d, note_prefix="note", notes_display, note_list_id, user_note_field=null, profile_pic_field=null) { - return (function() { +function removeNote(d, note_prefix = "note", notes_display, note_list_id, user_note_field = null, profile_pic_field = null) { + return (function () { let new_notes_display = []; let html = ""; notes_display.forEach(function (disp) { @@ -166,7 +167,7 @@ function removeNote(d, note_prefix="note", notes_display, note_list_id, user_not }); notes_display.length = 0; - new_notes_display.forEach(function(disp) { + new_notes_display.forEach(function (disp) { notes_display.push(disp); }); @@ -174,7 +175,7 @@ function removeNote(d, note_prefix="note", notes_display, note_list_id, user_not notes_display.forEach(function (disp) { let obj = $("#" + note_prefix + "_" + disp.id); obj.click(removeNote(disp, note_prefix, notes_display, note_list_id, user_note_field, profile_pic_field)); - obj.hover(function() { + obj.hover(function () { if (disp.note) displayNote(disp.note, disp.name, user_note_field, profile_pic_field); }); @@ -199,18 +200,18 @@ function removeNote(d, note_prefix="note", notes_display, note_list_id, user_not * the associated note is not displayed. * Useful for a consumption if the item is selected before. */ -function autoCompleteNote(field_id, alias_matched_id, note_list_id, notes, notes_display, alias_prefix="alias", - note_prefix="note", user_note_field=null, profile_pic_field=null, alias_click=null) { +function autoCompleteNote(field_id, alias_matched_id, note_list_id, notes, notes_display, alias_prefix = "alias", + note_prefix = "note", user_note_field = null, profile_pic_field = null, alias_click = null) { let field = $("#" + field_id); // When the user clicks on the search field, it is immediately cleared - field.click(function() { + field.click(function () { field.val(""); }); let old_pattern = null; // When the user type "Enter", the first alias is clicked - field.keypress(function(event) { + field.keypress(function (event) { if (event.originalEvent.charCode === 13 && notes.length > 0) { let li_obj = $("#" + alias_matched_id + " li").first(); displayNote(notes[0], li_obj.text(), user_note_field, profile_pic_field); @@ -219,7 +220,7 @@ function autoCompleteNote(field_id, alias_matched_id, note_list_id, notes, notes }); // When the user type something, the matched aliases are refreshed - field.keyup(function(e) { + field.keyup(function (e) { if (e.originalEvent.charCode === 13) return; @@ -233,7 +234,7 @@ function autoCompleteNote(field_id, alias_matched_id, note_list_id, notes, notes let aliases_matched_obj = $("#" + alias_matched_id); let aliases_matched_html = ""; // get matched Alias with note associated - if(pattern == ""){ + if (pattern === "") { aliases_matched_obj = $("#" + alias_matched_id); aliases_matched_html = ""; aliases_matched_obj.html("") @@ -242,81 +243,83 @@ function autoCompleteNote(field_id, alias_matched_id, note_list_id, notes, notes } $.getJSON("/api/note/consumer/?format=json&alias=" - + pattern - + "&search=user|club&ordering=normalized_name", - function(consumers){ - // The response arrived too late, we stop the request - if (pattern !== $("#" + field_id).val()) - return; - consumers.results.forEach(function (consumer){ - let note = consumer.note; - extra_css = displayStyle(note.balance); - aliases_matched_html += li(alias_prefix + '_' + consumer.id, - consumer.name, - extra_css); - notes.push(note); - }); - aliases_matched_obj.html(aliases_matched_html); - consumers.results.forEach(function(consumer){ - let note = consumer.note; - let consumer_obj = $("#" + alias_prefix+ "_" + consumer.id); - consumer_obj.hover(function(){ - displayNote(consumer.note, consumer.name, user_note_field,profile_pic_field) + + pattern + + "&search=user|club&ordering=normalized_name", + function (consumers) { + // The response arrived too late, we stop the request + if (pattern !== $("#" + field_id).val()) + return; + consumers.results.forEach(function (consumer) { + let note = consumer.note; + note.email_confirmed = consumer.email_confirmed; + let extra_css = displayStyle(note); + aliases_matched_html += li(alias_prefix + '_' + consumer.id, + consumer.name, + extra_css); + notes.push(note); }); - consumer_obj.click(function(){ - field.val(""); old_pattern = ""; // reset input field - var disp = null; - notes_display.forEach(function (d) { - // We compare the note ids - if (d.id === note.id) { - d.quantity += 1; - disp = d; + aliases_matched_obj.html(aliases_matched_html); + consumers.results.forEach(function (consumer) { + let note = consumer.note; + let consumer_obj = $("#" + alias_prefix + "_" + consumer.id); + consumer_obj.hover(function () { + displayNote(consumer.note, consumer.name, user_note_field, profile_pic_field) + }); + consumer_obj.click(function () { + field.val(""); + old_pattern = ""; // reset input field + var disp = null; + notes_display.forEach(function (d) { + // We compare the note ids + if (d.id === note.id) { + d.quantity += 1; + disp = d; + } + }); + // In the other case, we add a new emitter + if (disp == null) { + disp = { + name: consumer.name, + id: consumer.id, + note: note, + quantity: 1 + }; + notes_display.push(disp); } - }); - // In the other case, we add a new emitter - if (disp == null) { - disp = { - name: consumer.name, - id: consumer.id, - note: note, - quantity: 1 - }; - notes_display.push(disp); - } - // If the function alias_click exists, it is called. If it doesn't return true, then the notes are - // note displayed. Useful for a consumption when a button is already clicked - if (alias_click && !alias_click()) - return; + // If the function alias_click exists, it is called. If it doesn't return true, then the notes are + // note displayed. Useful for a consumption when a button is already clicked + if (alias_click && !alias_click()) + return; - let note_list = $("#" + note_list_id); - let html = ""; - notes_display.forEach(function (disp) { - html += li(note_prefix + "_" + disp.id, - disp.name - + "" - + disp.quantity + "", - displayStyle(disp.note.balance)); - }); - - // Emitters are displayed - note_list.html(html); - - notes_display.forEach(function (disp) { - let line_obj = $("#" + note_prefix + "_" + disp.id); - // Hover an emitter display also the profile picture - line_obj.hover(function () { - displayNote(disp.note, disp.name, user_note_field, profile_pic_field); + let note_list = $("#" + note_list_id); + let html = ""; + notes_display.forEach(function (disp) { + html += li(note_prefix + "_" + disp.id, + disp.name + + "" + + disp.quantity + "", + displayStyle(disp.note.balance)); }); - // When an emitter is clicked, it is removed - line_obj.click(removeNote(disp, note_prefix, notes_display, note_list_id, user_note_field, - profile_pic_field)); - }); - }) - }); + // Emitters are displayed + note_list.html(html); - });// end getJSON alias + notes_display.forEach(function (disp) { + let line_obj = $("#" + note_prefix + "_" + disp.id); + // Hover an emitter display also the profile picture + line_obj.hover(function () { + displayNote(disp.note, disp.name, user_note_field, profile_pic_field); + }); + + // When an emitter is clicked, it is removed + line_obj.click(removeNote(disp, note_prefix, notes_display, note_list_id, user_note_field, + profile_pic_field)); + }); + }) + }); + + });// end getJSON alias }); }// end function autocomplete @@ -347,7 +350,7 @@ function de_validate(id, validated) { // error if this method doesn't exist. Please define it. refreshHistory(); }, - error: function(err) { + error: function (err) { addMsg("Une erreur est survenue lors de la validation/dévalidation " + "de cette transaction : " + err.responseText, "danger"); diff --git a/templates/member/user_list.html b/templates/member/user_list.html index 0bcd7e89..68e23166 100644 --- a/templates/member/user_list.html +++ b/templates/member/user_list.html @@ -1,6 +1,7 @@ {% extends "base.html" %} {% load render_table from django_tables2 %} -{% load crispy_forms_tags%} +{% load crispy_forms_tags %} +{% load i18n %} {% block content %} From cf67e17e85dc565429df3151d7b5dbc1b7125315 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 10 Apr 2020 19:50:42 +0200 Subject: [PATCH 10/32] Do not use JavaScript to hide double conso after loading --- static/js/consos.js | 6 ++---- templates/note/conso_form.html | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/static/js/consos.js b/static/js/consos.js index 9450febc..943dbca3 100644 --- a/static/js/consos.js +++ b/static/js/consos.js @@ -26,7 +26,7 @@ $(document).ready(function() { // Switching in double consumptions mode should update the layout let double_conso_obj = $("#double_conso"); double_conso_obj.click(function() { - $("#consos_list_div").show(); + $("#consos_list_div").attr('class', 'col-xl-5'); $("#infos_div").attr('class', 'col-sm-5 col-xl-6'); $("#note_infos_div").attr('class', 'col-xl-3'); $("#user_select_div").attr('class', 'col-xl-4'); @@ -46,7 +46,7 @@ $(document).ready(function() { let single_conso_obj = $("#single_conso"); single_conso_obj.click(function() { - $("#consos_list_div").hide(); + $("#consos_list_div").attr('class', 'col-xl-5 d-none'); $("#infos_div").attr('class', 'col-sm-5 col-md-4'); $("#note_infos_div").attr('class', 'col-xl-5'); $("#user_select_div").attr('class', 'col-xl-7'); @@ -74,8 +74,6 @@ $(document).ready(function() { double_conso_obj.removeAttr('checked'); $("label[for='double_conso']").attr('class', 'btn btn-sm btn-outline-primary'); - $("#consos_list_div").hide(); - $("#consume_all").click(consumeAll); }); diff --git a/templates/note/conso_form.html b/templates/note/conso_form.html index 36659849..fd0923f2 100644 --- a/templates/note/conso_form.html +++ b/templates/note/conso_form.html @@ -42,7 +42,7 @@
    -
    +

    @@ -150,7 +150,7 @@ {% endblock %} {% block extrajavascript %} - + From b90ff59d989f360e47924d5af9a79d27b84bda1f Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 10 Apr 2020 22:46:57 +0200 Subject: [PATCH 21/32] Update tooltip position after new emitter --- static/js/base.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/static/js/base.js b/static/js/base.js index 02746302..af8eb8bf 100644 --- a/static/js/base.js +++ b/static/js/base.js @@ -317,6 +317,9 @@ function autoCompleteNote(field_id, note_list_id, notes, notes_display, alias_pr // Emitters are displayed note_list.html(html); + // Update tooltip position + field.tooltip('update'); + notes_display.forEach(function (disp) { let line_obj = $("#" + note_prefix + "_" + disp.id); // Hover an emitter display also the profile picture From 45c8fdf1c14a0b6a7e00644503d2851aed361914 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 10 Apr 2020 22:47:59 +0200 Subject: [PATCH 22/32] Revert margin for search field --- templates/note/conso_form.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/note/conso_form.html b/templates/note/conso_form.html index 35eff32c..d55da8b7 100644 --- a/templates/note/conso_form.html +++ b/templates/note/conso_form.html @@ -34,7 +34,7 @@

    {# User search with autocompletion #} -
    + From 5c1e3dd0ca58742c549f38008f70d326253d5eb4 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 10 Apr 2020 22:51:26 +0200 Subject: [PATCH 23/32] Make tooltips opaque again --- templates/base.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/templates/base.html b/templates/base.html index 44bc8c82..7cfc474b 100644 --- a/templates/base.html +++ b/templates/base.html @@ -59,6 +59,9 @@ SPDX-License-Identifier: GPL-3.0-or-later cursor: pointer; text-decoration: underline; } + .tooltip.show { + opacity: 1; /* opaque tooltip */ + } .tooltip-inner { background-color: #fff; box-shadow: 0 .5rem 1rem rgba(0,0,0,.15); From 46b5f537bc7504cc2f2e42163a3df64da2a730a2 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 10 Apr 2020 23:04:25 +0200 Subject: [PATCH 24/32] Fix tooltip inner selecter --- static/js/base.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/js/base.js b/static/js/base.js index af8eb8bf..bad8ad97 100644 --- a/static/js/base.js +++ b/static/js/base.js @@ -223,7 +223,7 @@ function autoCompleteNote(field_id, note_list_id, notes, notes_display, alias_pr // When the user type "Enter", the first alias is clicked field.keypress(function (event) { if (event.originalEvent.charCode === 13 && notes.length > 0) { - let li_obj = $(".tooltip-inner ul li").first(); + let li_obj = field.parent().find("ul li").first(); displayNote(notes[0], li_obj.text(), user_note_field, profile_pic_field); li_obj.trigger("click"); } From 700ad7c9f706e00b49e034788b993157808e808c Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 10 Apr 2020 23:15:25 +0200 Subject: [PATCH 25/32] Make consume section more bootstrap --- templates/note/conso_form.html | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/templates/note/conso_form.html b/templates/note/conso_form.html index d55da8b7..89a92790 100644 --- a/templates/note/conso_form.html +++ b/templates/note/conso_form.html @@ -28,7 +28,7 @@ {% trans "Consum" %}

    -
    +
    @@ -48,11 +48,15 @@ {% trans "Select consumptions" %}

    -
      -
    - +
    +
      +
    +
    +
    From 7af76899e3591c03ccbf6fc4c33153f2ac5b1647 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 10 Apr 2020 23:40:19 +0200 Subject: [PATCH 26/32] Simplify grids --- static/js/consos.js | 8 ++------ templates/note/conso_form.html | 4 ++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/static/js/consos.js b/static/js/consos.js index 11ad7302..2fa77249 100644 --- a/static/js/consos.js +++ b/static/js/consos.js @@ -26,10 +26,8 @@ $(document).ready(function() { // Switching in double consumptions mode should update the layout $("#double_conso").click(function() { $("#consos_list_div").removeClass('d-none'); - $("#infos_div").attr('class', 'col-sm-5 col-xl-6'); - $("#note_infos_div").attr('class', 'col-xl-3'); $("#user_select_div").attr('class', 'col-xl-4'); - $("#buttons_div").attr('class', 'col-sm-7 col-xl-6'); + $("#infos_div").attr('class', 'col-sm-5 col-xl-6'); let note_list_obj = $("#note_list"); if (buttons.length > 0 && note_list_obj.text().length > 0) { @@ -45,10 +43,8 @@ $(document).ready(function() { $("#single_conso").click(function() { $("#consos_list_div").addClass('d-none'); - $("#infos_div").attr('class', 'col-sm-5 col-md-4'); - $("#note_infos_div").attr('class', 'col-xl-5'); $("#user_select_div").attr('class', 'col-xl-7'); - $("#buttons_div").attr('class', 'col-sm-7 col-md-8'); + $("#infos_div").attr('class', 'col-sm-5 col-md-4'); let consos_list_obj = $("#consos_list"); if (buttons.length > 0) { diff --git a/templates/note/conso_form.html b/templates/note/conso_form.html index 89a92790..451d8a27 100644 --- a/templates/note/conso_form.html +++ b/templates/note/conso_form.html @@ -10,7 +10,7 @@
    {# User details column #} -
    +
    @@ -63,7 +63,7 @@
    {# Buttons column #} -
    +
    {# Show last used buttons #}
    From a609d7c9956790eda1e1d9b30ce096336c875950 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 10 Apr 2020 23:41:13 +0200 Subject: [PATCH 27/32] Fix credit/debit tabs --- apps/treasury/signals.py | 4 +- static/js/transfer.js | 65 ++++++++++++++++++++++++++++ templates/note/transaction_form.html | 52 +--------------------- 3 files changed, 69 insertions(+), 52 deletions(-) diff --git a/apps/treasury/signals.py b/apps/treasury/signals.py index 54c19c09..188be1a7 100644 --- a/apps/treasury/signals.py +++ b/apps/treasury/signals.py @@ -1,6 +1,7 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later +from note.models import NoteSpecial from treasury.models import SpecialTransactionProxy, RemittanceType @@ -8,5 +9,6 @@ def save_special_transaction(instance, created, **kwargs): """ When a special transaction is created, we create its linked proxy """ - if created and RemittanceType.objects.filter(note=instance.source).exists(): + if created and isinstance(instance.source, NoteSpecial) \ + and RemittanceType.objects.filter(note=instance.source).exists(): SpecialTransactionProxy.objects.create(transaction=instance, remittance=None).save() diff --git a/static/js/transfer.js b/static/js/transfer.js index 69fafac5..78a8ca08 100644 --- a/static/js/transfer.js +++ b/static/js/transfer.js @@ -34,6 +34,9 @@ $(document).ready(function() { if ($("#type_credit").is(":checked") || $("#type_debit").is(":checked")) { let arr = $("#type_credit").is(":checked") ? dests_notes_display : sources_notes_display; + if (arr.length === 0) + return; + let last = arr[arr.length - 1]; arr.length = 0; arr.push(last); @@ -65,6 +68,68 @@ $(document).ready(function() { autoCompleteNote("dest_note", "dest_note_list", dests, dests_notes_display, "dest_alias", "dest_note", "user_note", "profile_pic", checkUniqueNote); + let source = $("#source_note"); + let dest = $("#dest_note"); + + $("#type_gift").click(function() { + $("#special_transaction_div").addClass('d-none'); + source.attr('disabled', true); + source.val(username); + source.tooltip('hide'); + $("#source_note_list").addClass('d-none'); + dest.attr('disabled', false); + $("#dest_note_list").removeClass('d-none'); + }); + + $("#type_transfer").click(function() { + $("#special_transaction_div").addClass('d-none'); + source.attr('disabled', false); + $("#source_note_list").removeClass('d-none'); + dest.attr('disabled', false); + $("#dest_note_list").removeClass('d-none'); + }); + + $("#type_credit").click(function() { + $("#special_transaction_div").removeClass('d-none'); + $("#source_note_list").addClass('d-none'); + $("#dest_note_list").removeClass('d-none'); + source.attr('disabled', true); + source.val($("#credit_type option:selected").text()); + source.tooltip('hide'); + dest.attr('disabled', false); + dest.val(''); + dest.tooltip('hide'); + + if (dests_notes_display.length > 1) { + $("#dest_note_list").html(''); + dests_notes_display.length = 0; + } + }); + + $("#type_debit").click(function() { + $("#special_transaction_div").removeClass('d-none'); + $("#source_note_list").removeClass('d-none'); + $("#dest_note_list").addClass('d-none'); + source.attr('disabled', false); + source.val(''); + source.tooltip('hide'); + dest.attr('disabled', true); + dest.val($("#credit_type option:selected").text()); + dest.tooltip('hide'); + + if (sources_notes_display.length > 1) { + $("#source_note_list").html(''); + sources_notes_display.length = 0; + } + }); + + $("#credit_type").change(function() { + let type = $("#credit_type option:selected").text(); + if ($("#type_credit").is(":checked")) + source.val(type); + else + dest.val(type); + }); // Ensure we begin in gift mode. Removing these lines may cause problems when reloading. let type_gift = $("#type_gift"); // Default mode diff --git a/templates/note/transaction_form.html b/templates/note/transaction_form.html index d1cafa1f..c252f636 100644 --- a/templates/note/transaction_form.html +++ b/templates/note/transaction_form.html @@ -160,57 +160,7 @@ SPDX-License-Identifier: GPL-2.0-or-later TRANSFER_POLYMORPHIC_CTYPE = {{ polymorphic_ctype }}; SPECIAL_TRANSFER_POLYMORPHIC_CTYPE = {{ special_polymorphic_ctype }}; user_id = {{ user.note.pk }}; - - source = $("#source_note"); - dest = $("#dest_note"); - - $("#type_gift").click(function() { - $("#special_transaction_div").addClass('d-none'); - source.attr('disabled', true); - source.val("{{ user.username }}"); - source.tooltip('hide'); - $("#source_note_list").addClass('d-none'); - dest.attr('disabled', false); - $("#dest_note_list").removeClass('d-none'); - }); - - $("#type_transfer").click(function() { - $("#special_transaction_div").addClass('d-none'); - source.attr('disabled', false); - $("#source_note_list").removeClass('d-none'); - dest.attr('disabled', false); - $("#dest_note_list").removeClass('d-none'); - }); - - $("#type_credit").click(function() { - $("#special_transaction_div").removeClass('d-none'); - $("#source_note_list").addClass('d-none'); - $("#dest_note_list").removeClass('d-none'); - source.attr('disabled', true); - source.val($("#credit_type option:selected").text()); - source.tooltip('hide'); - dest.attr('disabled', false); - dest.val(''); - }); - - $("#type_debit").click(function() { - $("#special_transaction_div").removeClass('d-none'); - $("#source_note_list").removeClass('d-none'); - $("#dest_note_list").addClass('d-none'); - source.attr('disabled', false); - source.val(''); - dest.attr('disabled', true); - dest.val($("#credit_type option:selected").text()); - dest.tooltip('hide'); - }); - - $("#credit_type").change(function() { - let type = $("#credit_type option:selected").text(); - if ($("#type_credit").is(":checked")) - source.val(type); - else - dest.val(type); - }); + username = "{{ user.username }}"; {% endblock %} From d96c40a00f57823e310e2d1723cee794ce2e75aa Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 10 Apr 2020 23:46:16 +0200 Subject: [PATCH 28/32] Style was removed when a note was removed --- static/js/base.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/static/js/base.js b/static/js/base.js index bad8ad97..db12dae9 100644 --- a/static/js/base.js +++ b/static/js/base.js @@ -162,7 +162,8 @@ function removeNote(d, note_prefix = "note", notes_display, note_list_id, user_n disp.quantity -= disp.id === d.id ? 1 : 0; new_notes_display.push(disp); html += li(note_prefix + "_" + disp.id, disp.name - + "" + disp.quantity + ""); + + "" + disp.quantity + "", + displayStyle(disp.note)); } }); From 2bc20480767a16c9a9b8f02e0f82c2a64643c5c1 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 27 Apr 2020 03:21:13 +0200 Subject: [PATCH 29/32] RecurrentTransaction amount history --- apps/note/forms.py | 8 +- apps/note/views.py | 28 ++++ locale/de/LC_MESSAGES/django.po | 135 ++++++++------- locale/fr/LC_MESSAGES/django.po | 165 +++++++++++-------- templates/note/transactiontemplate_form.html | 28 +++- 5 files changed, 220 insertions(+), 144 deletions(-) diff --git a/apps/note/forms.py b/apps/note/forms.py index 50f226f2..bc479e20 100644 --- a/apps/note/forms.py +++ b/apps/note/forms.py @@ -4,7 +4,7 @@ from django import forms from django.contrib.contenttypes.models import ContentType from django.utils.translation import gettext_lazy as _ -from note_kfet.inputs import Autocomplete +from note_kfet.inputs import Autocomplete, AmountInput from .models import TransactionTemplate, NoteClub @@ -24,11 +24,6 @@ class TransactionTemplateForm(forms.ModelForm): model = TransactionTemplate fields = '__all__' - # Le champ de destination est remplacé par un champ d'auto-complétion. - # Quand des lettres sont tapées, une requête est envoyée sur l'API d'auto-complétion - # et récupère les aliases valides - # Pour force le type d'une note, il faut rajouter le paramètre : - # forward=(forward.Const('TYPE', 'note_type') où TYPE est dans {user, club, special} widgets = { 'destination': Autocomplete( @@ -41,4 +36,5 @@ class TransactionTemplateForm(forms.ModelForm): 'placeholder': 'Note ...', }, ), + 'amount': AmountInput(), } diff --git a/apps/note/views.py b/apps/note/views.py index 88d47847..85f31d7e 100644 --- a/apps/note/views.py +++ b/apps/note/views.py @@ -1,5 +1,6 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later +import json from django.conf import settings from django.contrib.auth.mixins import LoginRequiredMixin @@ -80,6 +81,33 @@ class TransactionTemplateUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, Up form_class = TransactionTemplateForm success_url = reverse_lazy('note:template_list') + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + if "logs" in settings.INSTALLED_APPS: + from logs.models import Changelog + update_logs = Changelog.objects.filter( + model=ContentType.objects.get_for_model(TransactionTemplate), + instance_pk=self.object.pk, + action="edit", + ) + price_history = [] + for log in update_logs.all(): + old_dict = json.loads(log.previous) + new_dict = json.loads(log.data) + old_price = old_dict["amount"] + new_price = new_dict["amount"] + if old_price != new_price: + price_history.append(dict(price=old_price, time=log.timestamp)) + + price_history.append(dict(price=self.object.amount, time=None)) + + price_history.reverse() + + context["price_history"] = price_history + + return context + class ConsoView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView): """ diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index f616ffd6..3daca779 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-09 21:59+0200\n" +"POT-Creation-Date: 2020-04-27 03:19+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -19,27 +19,27 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: apps/activity/apps.py:10 apps/activity/models.py:102 -#: apps/activity/models.py:111 +#: apps/activity/models.py:117 msgid "activity" msgstr "" -#: apps/activity/forms.py:45 apps/activity/models.py:208 +#: apps/activity/forms.py:45 apps/activity/models.py:213 msgid "You can't invite someone once the activity is started." msgstr "" -#: apps/activity/forms.py:48 apps/activity/models.py:211 +#: apps/activity/forms.py:48 apps/activity/models.py:216 msgid "This activity is not validated yet." msgstr "" -#: apps/activity/forms.py:58 apps/activity/models.py:219 +#: apps/activity/forms.py:58 apps/activity/models.py:224 msgid "This person has been already invited 5 times this year." msgstr "" -#: apps/activity/forms.py:62 apps/activity/models.py:223 +#: apps/activity/forms.py:62 apps/activity/models.py:228 msgid "This person is already invited." msgstr "" -#: apps/activity/forms.py:66 apps/activity/models.py:227 +#: apps/activity/forms.py:66 apps/activity/models.py:232 msgid "You can't invite more than 3 people to this activity." msgstr "" @@ -113,57 +113,57 @@ msgstr "" msgid "activities" msgstr "" -#: apps/activity/models.py:116 +#: apps/activity/models.py:122 msgid "entry time" msgstr "" -#: apps/activity/models.py:122 apps/note/apps.py:14 +#: apps/activity/models.py:128 apps/note/apps.py:14 #: apps/note/models/notes.py:58 msgid "note" msgstr "" -#: apps/activity/models.py:133 templates/activity/activity_entry.html:38 +#: apps/activity/models.py:139 templates/activity/activity_entry.html:38 msgid "entry" msgstr "" -#: apps/activity/models.py:134 templates/activity/activity_entry.html:38 +#: apps/activity/models.py:140 templates/activity/activity_entry.html:38 msgid "entries" msgstr "" -#: apps/activity/models.py:141 +#: apps/activity/models.py:146 msgid "Already entered on " msgstr "" -#: apps/activity/models.py:141 apps/activity/tables.py:54 +#: apps/activity/models.py:146 apps/activity/tables.py:54 msgid "{:%Y-%m-%d %H:%M:%S}" msgstr "" -#: apps/activity/models.py:149 +#: apps/activity/models.py:154 msgid "The balance is negative." msgstr "" -#: apps/activity/models.py:179 +#: apps/activity/models.py:184 msgid "last name" msgstr "" -#: apps/activity/models.py:184 templates/member/profile_info.html:14 +#: apps/activity/models.py:189 templates/member/profile_info.html:14 #: templates/registration/future_profile_detail.html:16 msgid "first name" msgstr "" -#: apps/activity/models.py:191 +#: apps/activity/models.py:196 msgid "inviter" msgstr "" -#: apps/activity/models.py:232 +#: apps/activity/models.py:237 msgid "guest" msgstr "" -#: apps/activity/models.py:233 +#: apps/activity/models.py:238 msgid "guests" msgstr "" -#: apps/activity/models.py:245 +#: apps/activity/models.py:250 msgid "Invitation" msgstr "" @@ -186,7 +186,7 @@ msgstr "" #: apps/activity/tables.py:79 apps/member/forms.py:80 #: apps/registration/forms.py:60 apps/treasury/forms.py:123 -#: templates/note/transaction_form.html:97 +#: templates/note/transaction_form.html:126 msgid "First name" msgstr "" @@ -198,11 +198,11 @@ msgstr "" msgid "Balance" msgstr "" -#: apps/activity/views.py:45 templates/base.html:106 +#: apps/activity/views.py:46 templates/base.html:121 msgid "Activities" msgstr "" -#: apps/activity/views.py:154 +#: apps/activity/views.py:160 msgid "Entry for activity \"{}\"" msgstr "" @@ -296,7 +296,7 @@ msgid "Credit amount" msgstr "" #: apps/member/forms.py:85 apps/registration/forms.py:65 -#: apps/treasury/forms.py:125 templates/note/transaction_form.html:103 +#: apps/treasury/forms.py:125 templates/note/transaction_form.html:132 msgid "Bank" msgstr "" @@ -666,9 +666,9 @@ msgid "transactions" msgstr "" #: apps/note/models/transactions.py:207 -#: templates/activity/activity_entry.html:13 templates/base.html:84 +#: templates/activity/activity_entry.html:13 templates/base.html:99 #: templates/note/transaction_form.html:19 -#: templates/note/transaction_form.html:145 +#: templates/note/transaction_form.html:140 msgid "Transfer" msgstr "" @@ -719,15 +719,15 @@ msgid "Delete" msgstr "" #: apps/note/tables.py:146 templates/member/club_info.html:55 -#: templates/note/conso_form.html:121 +#: templates/note/conso_form.html:128 msgid "Edit" msgstr "" -#: apps/note/views.py:40 +#: apps/note/views.py:41 msgid "Transfer money" msgstr "" -#: apps/note/views.py:109 templates/base.html:79 +#: apps/note/views.py:137 templates/base.html:94 msgid "Consumptions" msgstr "" @@ -810,7 +810,7 @@ msgid "" "The entered amount is not enough for the memberships, should be at least {}" msgstr "" -#: apps/treasury/apps.py:12 templates/base.html:111 +#: apps/treasury/apps.py:12 templates/base.html:126 msgid "Treasury" msgstr "" @@ -836,7 +836,7 @@ msgid "You can't change the type of the remittance." msgstr "" #: apps/treasury/forms.py:127 apps/treasury/tables.py:47 -#: templates/note/transaction_form.html:133 +#: templates/note/transaction_form.html:95 #: templates/treasury/remittance_form.html:18 msgid "Amount" msgstr "" @@ -857,7 +857,7 @@ msgstr "" msgid "Description" msgstr "" -#: apps/treasury/models.py:46 templates/note/transaction_form.html:91 +#: apps/treasury/models.py:46 templates/note/transaction_form.html:120 msgid "Name" msgstr "" @@ -1052,19 +1052,19 @@ msgstr "" msgid "The ENS Paris-Saclay BDE note." msgstr "" -#: templates/base.html:89 +#: templates/base.html:104 msgid "Users" msgstr "" -#: templates/base.html:94 +#: templates/base.html:109 msgid "Clubs" msgstr "" -#: templates/base.html:100 +#: templates/base.html:115 msgid "Registrations" msgstr "" -#: templates/base.html:150 +#: templates/base.html:165 msgid "" "Your e-mail address is not validated. Please check your mail inbox and click " "on the validation link." @@ -1227,36 +1227,41 @@ msgstr "" msgid "Save Changes" msgstr "" -#: templates/member/user_list.html:14 +#: templates/member/user_list.html:15 #: templates/registration/future_user_list.html:17 msgid "There is no pending user with this pattern." msgstr "" -#: templates/note/conso_form.html:28 templates/note/transaction_form.html:55 -msgid "Select emitters" +#: templates/note/conso_form.html:28 +msgid "Consum" msgstr "" -#: templates/note/conso_form.html:45 +#: templates/note/conso_form.html:39 templates/note/transaction_form.html:61 +#: templates/note/transaction_form.html:76 +msgid "Name or alias..." +msgstr "" + +#: templates/note/conso_form.html:48 msgid "Select consumptions" msgstr "" -#: templates/note/conso_form.html:51 +#: templates/note/conso_form.html:57 msgid "Consume!" msgstr "" -#: templates/note/conso_form.html:64 +#: templates/note/conso_form.html:71 msgid "Most used buttons" msgstr "" -#: templates/note/conso_form.html:126 +#: templates/note/conso_form.html:134 msgid "Single consumptions" msgstr "" -#: templates/note/conso_form.html:130 +#: templates/note/conso_form.html:139 msgid "Double consumptions" msgstr "" -#: templates/note/conso_form.html:141 templates/note/transaction_form.html:152 +#: templates/note/conso_form.html:150 templates/note/transaction_form.html:151 msgid "Recent transactions history" msgstr "" @@ -1264,36 +1269,42 @@ msgstr "" msgid "Gift" msgstr "" -#: templates/note/transaction_form.html:73 -msgid "External payment" +#: templates/note/transaction_form.html:55 +msgid "Select emitters" msgstr "" -#: templates/note/transaction_form.html:81 -msgid "Transfer type" -msgstr "" - -#: templates/note/transaction_form.html:116 -#: templates/note/transaction_form.html:169 -#: templates/note/transaction_form.html:176 +#: templates/note/transaction_form.html:70 msgid "Select receivers" msgstr "" -#: templates/note/transaction_form.html:138 +#: templates/note/transaction_form.html:87 +msgid "Action" +msgstr "" + +#: templates/note/transaction_form.html:102 msgid "Reason" msgstr "" -#: templates/note/transaction_form.html:183 -msgid "Credit note" +#: templates/note/transaction_form.html:110 +msgid "Transfer type" msgstr "" -#: templates/note/transaction_form.html:190 -msgid "Debit note" -msgstr "" - -#: templates/note/transactiontemplate_form.html:6 +#: templates/note/transactiontemplate_form.html:10 msgid "Buttons list" msgstr "" +#: templates/note/transactiontemplate_form.html:21 +msgid "Price history" +msgstr "" + +#: templates/note/transactiontemplate_form.html:24 +msgid "Obsolete since" +msgstr "" + +#: templates/note/transactiontemplate_form.html:24 +msgid "Current price" +msgstr "" + #: templates/note/transactiontemplate_list.html:9 msgid "search button" msgstr "" diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 27636a65..51075884 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-09 21:59+0200\n" +"POT-Creation-Date: 2020-04-27 03:19+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -14,28 +14,28 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: apps/activity/apps.py:10 apps/activity/models.py:102 -#: apps/activity/models.py:111 +#: apps/activity/models.py:117 msgid "activity" msgstr "activité" -#: apps/activity/forms.py:45 apps/activity/models.py:208 +#: apps/activity/forms.py:45 apps/activity/models.py:213 msgid "You can't invite someone once the activity is started." msgstr "" "Vous ne pouvez pas inviter quelqu'un une fois que l'activité a démarré." -#: apps/activity/forms.py:48 apps/activity/models.py:211 +#: apps/activity/forms.py:48 apps/activity/models.py:216 msgid "This activity is not validated yet." msgstr "Cette activité n'est pas encore validée." -#: apps/activity/forms.py:58 apps/activity/models.py:219 +#: apps/activity/forms.py:58 apps/activity/models.py:224 msgid "This person has been already invited 5 times this year." msgstr "Cette personne a déjà été invitée 5 fois cette année." -#: apps/activity/forms.py:62 apps/activity/models.py:223 +#: apps/activity/forms.py:62 apps/activity/models.py:228 msgid "This person is already invited." msgstr "Cette personne est déjà invitée." -#: apps/activity/forms.py:66 apps/activity/models.py:227 +#: apps/activity/forms.py:66 apps/activity/models.py:232 msgid "You can't invite more than 3 people to this activity." msgstr "Vous ne pouvez pas inviter plus de 3 personnes à cette activité." @@ -109,57 +109,57 @@ msgstr "ouvrir" msgid "activities" msgstr "activités" -#: apps/activity/models.py:116 +#: apps/activity/models.py:122 msgid "entry time" msgstr "heure d'entrée" -#: apps/activity/models.py:122 apps/note/apps.py:14 +#: apps/activity/models.py:128 apps/note/apps.py:14 #: apps/note/models/notes.py:58 msgid "note" msgstr "note" -#: apps/activity/models.py:133 templates/activity/activity_entry.html:38 +#: apps/activity/models.py:139 templates/activity/activity_entry.html:38 msgid "entry" msgstr "entrée" -#: apps/activity/models.py:134 templates/activity/activity_entry.html:38 +#: apps/activity/models.py:140 templates/activity/activity_entry.html:38 msgid "entries" msgstr "entrées" -#: apps/activity/models.py:141 +#: apps/activity/models.py:146 msgid "Already entered on " msgstr "Déjà rentré le " -#: apps/activity/models.py:141 apps/activity/tables.py:54 +#: apps/activity/models.py:146 apps/activity/tables.py:54 msgid "{:%Y-%m-%d %H:%M:%S}" msgstr "{:%d/%m/%Y %H:%M:%S}" -#: apps/activity/models.py:149 +#: apps/activity/models.py:154 msgid "The balance is negative." msgstr "La note est en négatif." -#: apps/activity/models.py:179 +#: apps/activity/models.py:184 msgid "last name" msgstr "nom de famille" -#: apps/activity/models.py:184 templates/member/profile_info.html:14 +#: apps/activity/models.py:189 templates/member/profile_info.html:14 #: templates/registration/future_profile_detail.html:16 msgid "first name" msgstr "prénom" -#: apps/activity/models.py:191 +#: apps/activity/models.py:196 msgid "inviter" msgstr "hôte" -#: apps/activity/models.py:232 +#: apps/activity/models.py:237 msgid "guest" msgstr "invité" -#: apps/activity/models.py:233 +#: apps/activity/models.py:238 msgid "guests" msgstr "invités" -#: apps/activity/models.py:245 +#: apps/activity/models.py:250 msgid "Invitation" msgstr "Invitation" @@ -182,7 +182,7 @@ msgstr "Nom de famille" #: apps/activity/tables.py:79 apps/member/forms.py:80 #: apps/registration/forms.py:60 apps/treasury/forms.py:123 -#: templates/note/transaction_form.html:97 +#: templates/note/transaction_form.html:126 msgid "First name" msgstr "Prénom" @@ -194,11 +194,11 @@ msgstr "Note" msgid "Balance" msgstr "Solde du compte" -#: apps/activity/views.py:45 templates/base.html:106 +#: apps/activity/views.py:46 templates/base.html:121 msgid "Activities" msgstr "Activités" -#: apps/activity/views.py:154 +#: apps/activity/views.py:160 msgid "Entry for activity \"{}\"" msgstr "Entrées pour l'activité « {} »" @@ -292,7 +292,7 @@ msgid "Credit amount" msgstr "Montant à créditer" #: apps/member/forms.py:85 apps/registration/forms.py:65 -#: apps/treasury/forms.py:125 templates/note/transaction_form.html:103 +#: apps/treasury/forms.py:125 templates/note/transaction_form.html:132 msgid "Bank" msgstr "Banque" @@ -669,9 +669,9 @@ msgid "transactions" msgstr "transactions" #: apps/note/models/transactions.py:207 -#: templates/activity/activity_entry.html:13 templates/base.html:84 +#: templates/activity/activity_entry.html:13 templates/base.html:99 #: templates/note/transaction_form.html:19 -#: templates/note/transaction_form.html:145 +#: templates/note/transaction_form.html:140 msgid "Transfer" msgstr "Virement" @@ -722,15 +722,15 @@ msgid "Delete" msgstr "Supprimer" #: apps/note/tables.py:146 templates/member/club_info.html:55 -#: templates/note/conso_form.html:121 +#: templates/note/conso_form.html:128 msgid "Edit" msgstr "Éditer" -#: apps/note/views.py:40 +#: apps/note/views.py:41 msgid "Transfer money" msgstr "Transférer de l'argent" -#: apps/note/views.py:109 templates/base.html:79 +#: apps/note/views.py:137 templates/base.html:94 msgid "Consumptions" msgstr "Consommations" @@ -815,7 +815,7 @@ msgstr "" "Le montant crédité est trop faible pour adhérer, il doit être au minimum de " "{}" -#: apps/treasury/apps.py:12 templates/base.html:111 +#: apps/treasury/apps.py:12 templates/base.html:126 msgid "Treasury" msgstr "Trésorerie" @@ -841,7 +841,7 @@ msgid "You can't change the type of the remittance." msgstr "Vous ne pouvez pas changer le type de la remise." #: apps/treasury/forms.py:127 apps/treasury/tables.py:47 -#: templates/note/transaction_form.html:133 +#: templates/note/transaction_form.html:95 #: templates/treasury/remittance_form.html:18 msgid "Amount" msgstr "Montant" @@ -862,7 +862,7 @@ msgstr "Objet" msgid "Description" msgstr "Description" -#: apps/treasury/models.py:46 templates/note/transaction_form.html:91 +#: apps/treasury/models.py:46 templates/note/transaction_form.html:120 msgid "Name" msgstr "Nom" @@ -1057,19 +1057,19 @@ msgstr "Toutes les activités" msgid "The ENS Paris-Saclay BDE note." msgstr "La note du BDE de l'ENS Paris-Saclay." -#: templates/base.html:89 +#: templates/base.html:104 msgid "Users" msgstr "Utilisateurs" -#: templates/base.html:94 +#: templates/base.html:109 msgid "Clubs" msgstr "Clubs" -#: templates/base.html:100 +#: templates/base.html:115 msgid "Registrations" msgstr "Inscriptions" -#: templates/base.html:150 +#: templates/base.html:165 msgid "" "Your e-mail address is not validated. Please check your mail inbox and click " "on the validation link." @@ -1234,36 +1234,43 @@ msgstr "Voir mes adhésions" msgid "Save Changes" msgstr "Sauvegarder les changements" -#: templates/member/user_list.html:14 +#: templates/member/user_list.html:15 #: templates/registration/future_user_list.html:17 msgid "There is no pending user with this pattern." msgstr "Il n'y a pas d'inscription en attente avec cette entrée." -#: templates/note/conso_form.html:28 templates/note/transaction_form.html:55 -msgid "Select emitters" -msgstr "Sélection des émetteurs" +#: templates/note/conso_form.html:28 +#, fuzzy +#| msgid "Consume!" +msgid "Consum" +msgstr "Consommer !" -#: templates/note/conso_form.html:45 +#: templates/note/conso_form.html:39 templates/note/transaction_form.html:61 +#: templates/note/transaction_form.html:76 +msgid "Name or alias..." +msgstr "" + +#: templates/note/conso_form.html:48 msgid "Select consumptions" msgstr "Sélection des consommations" -#: templates/note/conso_form.html:51 +#: templates/note/conso_form.html:57 msgid "Consume!" msgstr "Consommer !" -#: templates/note/conso_form.html:64 +#: templates/note/conso_form.html:71 msgid "Most used buttons" msgstr "Boutons les plus utilisés" -#: templates/note/conso_form.html:126 +#: templates/note/conso_form.html:134 msgid "Single consumptions" msgstr "Consommations simples" -#: templates/note/conso_form.html:130 +#: templates/note/conso_form.html:139 msgid "Double consumptions" msgstr "Consommations doubles" -#: templates/note/conso_form.html:141 templates/note/transaction_form.html:152 +#: templates/note/conso_form.html:150 templates/note/transaction_form.html:151 msgid "Recent transactions history" msgstr "Historique des transactions récentes" @@ -1271,36 +1278,44 @@ msgstr "Historique des transactions récentes" msgid "Gift" msgstr "Don" -#: templates/note/transaction_form.html:73 -msgid "External payment" -msgstr "Paiement externe" +#: templates/note/transaction_form.html:55 +msgid "Select emitters" +msgstr "Sélection des émetteurs" -#: templates/note/transaction_form.html:81 -msgid "Transfer type" -msgstr "Type de transfert" - -#: templates/note/transaction_form.html:116 -#: templates/note/transaction_form.html:169 -#: templates/note/transaction_form.html:176 +#: templates/note/transaction_form.html:70 msgid "Select receivers" msgstr "Sélection des destinataires" -#: templates/note/transaction_form.html:138 +#: templates/note/transaction_form.html:87 +#, fuzzy +#| msgid "action" +msgid "Action" +msgstr "Action" + +#: templates/note/transaction_form.html:102 msgid "Reason" msgstr "Raison" -#: templates/note/transaction_form.html:183 -msgid "Credit note" -msgstr "Note à recharger" +#: templates/note/transaction_form.html:110 +msgid "Transfer type" +msgstr "Type de transfert" -#: templates/note/transaction_form.html:190 -msgid "Debit note" -msgstr "Note à débiter" - -#: templates/note/transactiontemplate_form.html:6 +#: templates/note/transactiontemplate_form.html:10 msgid "Buttons list" msgstr "Liste des boutons" +#: templates/note/transactiontemplate_form.html:21 +msgid "Price history" +msgstr "Historique des prix" + +#: templates/note/transactiontemplate_form.html:24 +msgid "Obsolete since" +msgstr "Obsolète depuis" + +#: templates/note/transactiontemplate_form.html:24 +msgid "Current price" +msgstr "Prix actuel" + #: templates/note/transactiontemplate_list.html:9 msgid "search button" msgstr "Chercher un bouton" @@ -1334,15 +1349,16 @@ msgstr "Vous pouvez désormais vous connecter." msgid "" "You must pay now your membership in the Kfet to complete your registration." msgstr "" -"Vous devez désormais payer votre adhésion à la Kfet pour compléter votre inscription." +"Vous devez désormais payer votre adhésion à la Kfet pour compléter votre " +"inscription." #: templates/registration/email_validation_complete.html:13 msgid "" "The link was invalid. The token may have expired. Please send us an email to " "activate your account." msgstr "" -"Le lien est invalide. Le jeton a sans doute expiré. Merci de nous contacter pour " -"activer votre compte." +"Le lien est invalide. Le jeton a sans doute expiré. Merci de nous contacter " +"pour activer votre compte." #: templates/registration/future_profile_detail.html:56 msgid "Delete registration" @@ -1414,8 +1430,8 @@ msgid "" "After that, you'll have to wait that someone validates your account before " "you can log in. You will need to pay your membership in the Kfet." msgstr "" -"Après cela, vous devrez attendre que quelqu'un valide votre compte avant " -"de pouvoir vous connecter. Vous devrez payer votre adhésion à la Kfet." +"Après cela, vous devrez attendre que quelqu'un valide votre compte avant de " +"pouvoir vous connecter. Vous devrez payer votre adhésion à la Kfet." #: templates/registration/mails/email_validation_email.html:13 msgid "Thanks" @@ -1552,5 +1568,14 @@ msgstr "Il n'y a pas de transaction associée à une remise ouverte." msgid "Closed remittances" msgstr "Remises fermées" +#~ msgid "External payment" +#~ msgstr "Paiement externe" + +#~ msgid "Credit note" +#~ msgstr "Note à recharger" + +#~ msgid "Debit note" +#~ msgstr "Note à débiter" + #~ msgid "This membership is already renewed" #~ msgstr "Cette adhésion est déjà renouvelée" diff --git a/templates/note/transactiontemplate_form.html b/templates/note/transactiontemplate_form.html index 1f9a574a..26cd97b5 100644 --- a/templates/note/transactiontemplate_form.html +++ b/templates/note/transactiontemplate_form.html @@ -1,12 +1,28 @@ {% extends "base.html" %} + {% load static %} {% load i18n %} {% load crispy_forms_tags %} +{% load pretty_money %} + {% block content %} -

    {% trans "Buttons list" %}

    -
    -{% csrf_token %} -{{form|crispy}} - -
    +

    + {% trans "Buttons list" %} +

    +
    + {% csrf_token %} + {{form|crispy}} + +
    + + {% if price_history %} +
    + +

    {% trans "Price history" %}

    +
      + {% for price in price_history %} +
    • {{ price.price|pretty_money }} {% if price.time %}({% trans "Obsolete since" %} {{ price.time }}){% else %}({% trans "Current price" %}){% endif %}
    • + {% endfor %} +
    + {% endif %} {% endblock %} From 5ea531fe68bb72399341545eeb7e1e9db39e460e Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 27 Apr 2020 03:56:22 +0200 Subject: [PATCH 30/32] Filter buttons list with visible buttons only --- apps/note/models/transactions.py | 3 +- apps/note/tables.py | 3 +- locale/de/LC_MESSAGES/django.po | 45 +++++--- locale/fr/LC_MESSAGES/django.po | 45 +++++--- templates/note/transactiontemplate_form.html | 4 +- templates/note/transactiontemplate_list.html | 111 +++++++++++-------- 6 files changed, 125 insertions(+), 86 deletions(-) diff --git a/apps/note/models/transactions.py b/apps/note/models/transactions.py index 83f8f914..455ac841 100644 --- a/apps/note/models/transactions.py +++ b/apps/note/models/transactions.py @@ -214,8 +214,7 @@ class RecurrentTransaction(Transaction): template = models.ForeignKey( TransactionTemplate, - null=True, - on_delete=models.SET_NULL, + on_delete=models.PROTECT, ) category = models.ForeignKey( TemplateCategory, diff --git a/apps/note/tables.py b/apps/note/tables.py index 8504121c..a1385abc 100644 --- a/apps/note/tables.py +++ b/apps/note/tables.py @@ -129,13 +129,14 @@ class ButtonTable(tables.Table): 'table table-bordered condensed table-hover' } row_attrs = { - 'class': lambda record: 'table-row ' + 'table-success' if record.display else 'table-danger', + 'class': lambda record: 'table-row ' + ('table-success' if record.display else 'table-danger'), 'id': lambda record: "row-" + str(record.pk), 'data-href': lambda record: record.pk } model = TransactionTemplate exclude = ('id',) + order_by = ('type', '-display', 'destination__name', 'name',) edit = tables.LinkColumn('note:template_update', args=[A('pk')], diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index 3daca779..111f60b6 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-27 03:19+0200\n" +"POT-Creation-Date: 2020-04-27 03:55+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -46,7 +46,7 @@ msgstr "" #: apps/activity/models.py:23 apps/activity/models.py:48 #: apps/member/models.py:99 apps/member/models.py:202 #: apps/note/models/notes.py:188 apps/note/models/transactions.py:24 -#: apps/note/models/transactions.py:44 apps/note/models/transactions.py:237 +#: apps/note/models/transactions.py:44 apps/note/models/transactions.py:236 #: templates/member/club_info.html:13 templates/member/profile_info.html:14 #: templates/registration/future_profile_detail.html:16 msgid "name" @@ -238,12 +238,12 @@ msgstr "" msgid "create" msgstr "" -#: apps/logs/models.py:61 apps/note/tables.py:144 +#: apps/logs/models.py:61 apps/note/tables.py:145 #: templates/activity/activity_detail.html:67 msgid "edit" msgstr "" -#: apps/logs/models.py:62 apps/note/tables.py:120 apps/note/tables.py:149 +#: apps/logs/models.py:62 apps/note/tables.py:120 apps/note/tables.py:150 msgid "delete" msgstr "" @@ -672,33 +672,33 @@ msgstr "" msgid "Transfer" msgstr "" -#: apps/note/models/transactions.py:227 +#: apps/note/models/transactions.py:226 msgid "Template" msgstr "" -#: apps/note/models/transactions.py:242 +#: apps/note/models/transactions.py:241 msgid "first_name" msgstr "" -#: apps/note/models/transactions.py:247 +#: apps/note/models/transactions.py:246 msgid "bank" msgstr "" -#: apps/note/models/transactions.py:253 +#: apps/note/models/transactions.py:252 #: templates/activity/activity_entry.html:17 #: templates/note/transaction_form.html:24 msgid "Credit" msgstr "" -#: apps/note/models/transactions.py:253 templates/note/transaction_form.html:28 +#: apps/note/models/transactions.py:252 templates/note/transaction_form.html:28 msgid "Debit" msgstr "" -#: apps/note/models/transactions.py:269 apps/note/models/transactions.py:274 +#: apps/note/models/transactions.py:268 apps/note/models/transactions.py:273 msgid "membership transaction" msgstr "" -#: apps/note/models/transactions.py:270 +#: apps/note/models/transactions.py:269 msgid "membership transactions" msgstr "" @@ -714,11 +714,11 @@ msgstr "" msgid "No reason specified" msgstr "" -#: apps/note/tables.py:122 apps/note/tables.py:151 +#: apps/note/tables.py:122 apps/note/tables.py:152 msgid "Delete" msgstr "" -#: apps/note/tables.py:146 templates/member/club_info.html:55 +#: apps/note/tables.py:147 templates/member/club_info.html:55 #: templates/note/conso_form.html:128 msgid "Edit" msgstr "" @@ -819,6 +819,7 @@ msgstr "" #: templates/activity/activity_invite.html:8 #: templates/django_filters/rest_framework/form.html:5 #: templates/member/add_members.html:14 templates/member/club_form.html:9 +#: templates/note/transactiontemplate_form.html:15 #: templates/treasury/invoice_form.html:46 msgid "Submit" msgstr "" @@ -1306,22 +1307,30 @@ msgid "Current price" msgstr "" #: templates/note/transactiontemplate_list.html:9 -msgid "search button" +msgid "Search button" msgstr "" -#: templates/note/transactiontemplate_list.html:13 +#: templates/note/transactiontemplate_list.html:11 +msgid "Name of the button..." +msgstr "" + +#: templates/note/transactiontemplate_list.html:16 +msgid "Display visible buttons only" +msgstr "" + +#: templates/note/transactiontemplate_list.html:21 msgid "New button" msgstr "" -#: templates/note/transactiontemplate_list.html:20 +#: templates/note/transactiontemplate_list.html:28 msgid "buttons listing " msgstr "" -#: templates/note/transactiontemplate_list.html:70 +#: templates/note/transactiontemplate_list.html:86 msgid "button successfully deleted " msgstr "" -#: templates/note/transactiontemplate_list.html:74 +#: templates/note/transactiontemplate_list.html:90 msgid "Unable to delete button " msgstr "" diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 51075884..ab608942 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-27 03:19+0200\n" +"POT-Creation-Date: 2020-04-27 03:55+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -42,7 +42,7 @@ msgstr "Vous ne pouvez pas inviter plus de 3 personnes à cette activité." #: apps/activity/models.py:23 apps/activity/models.py:48 #: apps/member/models.py:99 apps/member/models.py:202 #: apps/note/models/notes.py:188 apps/note/models/transactions.py:24 -#: apps/note/models/transactions.py:44 apps/note/models/transactions.py:237 +#: apps/note/models/transactions.py:44 apps/note/models/transactions.py:236 #: templates/member/club_info.html:13 templates/member/profile_info.html:14 #: templates/registration/future_profile_detail.html:16 msgid "name" @@ -234,12 +234,12 @@ msgstr "Nouvelles données" msgid "create" msgstr "Créer" -#: apps/logs/models.py:61 apps/note/tables.py:144 +#: apps/logs/models.py:61 apps/note/tables.py:145 #: templates/activity/activity_detail.html:67 msgid "edit" msgstr "Modifier" -#: apps/logs/models.py:62 apps/note/tables.py:120 apps/note/tables.py:149 +#: apps/logs/models.py:62 apps/note/tables.py:120 apps/note/tables.py:150 msgid "delete" msgstr "Supprimer" @@ -675,33 +675,33 @@ msgstr "transactions" msgid "Transfer" msgstr "Virement" -#: apps/note/models/transactions.py:227 +#: apps/note/models/transactions.py:226 msgid "Template" msgstr "Bouton" -#: apps/note/models/transactions.py:242 +#: apps/note/models/transactions.py:241 msgid "first_name" msgstr "prénom" -#: apps/note/models/transactions.py:247 +#: apps/note/models/transactions.py:246 msgid "bank" msgstr "banque" -#: apps/note/models/transactions.py:253 +#: apps/note/models/transactions.py:252 #: templates/activity/activity_entry.html:17 #: templates/note/transaction_form.html:24 msgid "Credit" msgstr "Crédit" -#: apps/note/models/transactions.py:253 templates/note/transaction_form.html:28 +#: apps/note/models/transactions.py:252 templates/note/transaction_form.html:28 msgid "Debit" msgstr "Débit" -#: apps/note/models/transactions.py:269 apps/note/models/transactions.py:274 +#: apps/note/models/transactions.py:268 apps/note/models/transactions.py:273 msgid "membership transaction" msgstr "Transaction d'adhésion" -#: apps/note/models/transactions.py:270 +#: apps/note/models/transactions.py:269 msgid "membership transactions" msgstr "Transactions d'adhésion" @@ -717,11 +717,11 @@ msgstr "Cliquez pour valider" msgid "No reason specified" msgstr "Pas de motif spécifié" -#: apps/note/tables.py:122 apps/note/tables.py:151 +#: apps/note/tables.py:122 apps/note/tables.py:152 msgid "Delete" msgstr "Supprimer" -#: apps/note/tables.py:146 templates/member/club_info.html:55 +#: apps/note/tables.py:147 templates/member/club_info.html:55 #: templates/note/conso_form.html:128 msgid "Edit" msgstr "Éditer" @@ -824,6 +824,7 @@ msgstr "Trésorerie" #: templates/activity/activity_invite.html:8 #: templates/django_filters/rest_framework/form.html:5 #: templates/member/add_members.html:14 templates/member/club_form.html:9 +#: templates/note/transactiontemplate_form.html:15 #: templates/treasury/invoice_form.html:46 msgid "Submit" msgstr "Envoyer" @@ -1317,22 +1318,30 @@ msgid "Current price" msgstr "Prix actuel" #: templates/note/transactiontemplate_list.html:9 -msgid "search button" +msgid "Search button" msgstr "Chercher un bouton" -#: templates/note/transactiontemplate_list.html:13 +#: templates/note/transactiontemplate_list.html:11 +msgid "Name of the button..." +msgstr "Nom du bouton ..." + +#: templates/note/transactiontemplate_list.html:16 +msgid "Display visible buttons only" +msgstr "N'afficher que les boutons visibles uniquement" + +#: templates/note/transactiontemplate_list.html:21 msgid "New button" msgstr "Nouveau bouton" -#: templates/note/transactiontemplate_list.html:20 +#: templates/note/transactiontemplate_list.html:28 msgid "buttons listing " msgstr "Liste des boutons" -#: templates/note/transactiontemplate_list.html:70 +#: templates/note/transactiontemplate_list.html:86 msgid "button successfully deleted " msgstr "Le bouton a bien été supprimé" -#: templates/note/transactiontemplate_list.html:74 +#: templates/note/transactiontemplate_list.html:90 msgid "Unable to delete button " msgstr "Impossible de supprimer le bouton " diff --git a/templates/note/transactiontemplate_form.html b/templates/note/transactiontemplate_form.html index 26cd97b5..e4bc42a7 100644 --- a/templates/note/transactiontemplate_form.html +++ b/templates/note/transactiontemplate_form.html @@ -12,10 +12,10 @@
    {% csrf_token %} {{form|crispy}} - +
    - {% if price_history %} + {% if price_history and price_history.1 %}

    {% trans "Price history" %}

    diff --git a/templates/note/transactiontemplate_list.html b/templates/note/transactiontemplate_list.html index cf9bc5ed..b298f58a 100644 --- a/templates/note/transactiontemplate_list.html +++ b/templates/note/transactiontemplate_list.html @@ -6,9 +6,17 @@

    - {% trans "search button" %} + {% trans "Search button" %}

    - + +
    +
    + +
    +

    {% trans "New button" %}
    @@ -29,50 +37,63 @@ {% block extrajavascript %} {% endblock %} From 368d28574792c30baa352a684cc7177879b33ab5 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 27 Apr 2020 04:01:30 +0200 Subject: [PATCH 31/32] Display by default only visible buttons --- templates/note/transactiontemplate_list.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/templates/note/transactiontemplate_list.html b/templates/note/transactiontemplate_list.html index b298f58a..280f9faf 100644 --- a/templates/note/transactiontemplate_list.html +++ b/templates/note/transactiontemplate_list.html @@ -12,7 +12,7 @@
    @@ -94,6 +94,8 @@ $(document).ready(function() { $("#search_field").keyup(search_field_moved); $("#active_only").change(search_field_moved); + + search_field_moved(); }); {% endblock %} From 72642d470c645e5d9978e09ed83f7889bec83434 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 27 Apr 2020 04:08:02 +0200 Subject: [PATCH 32/32] Fix two translations --- locale/fr/LC_MESSAGES/django.po | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index ab608942..feb06dd8 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -1241,10 +1241,8 @@ msgid "There is no pending user with this pattern." msgstr "Il n'y a pas d'inscription en attente avec cette entrée." #: templates/note/conso_form.html:28 -#, fuzzy -#| msgid "Consume!" msgid "Consum" -msgstr "Consommer !" +msgstr "Consommer" #: templates/note/conso_form.html:39 templates/note/transaction_form.html:61 #: templates/note/transaction_form.html:76 @@ -1288,8 +1286,6 @@ msgid "Select receivers" msgstr "Sélection des destinataires" #: templates/note/transaction_form.html:87 -#, fuzzy -#| msgid "action" msgid "Action" msgstr "Action"