mirror of https://gitlab.crans.org/bde/nk20
Merge branch 'tranfer_front' into 'master'
Transfer front See merge request bde/nk20!76
This commit is contained in:
commit
0776ed416c
|
@ -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
|
||||
|
@ -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
|
||||
|
|
|
@ -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, \
|
||||
|
@ -97,6 +99,35 @@ class NotePolymorphicSerializer(PolymorphicSerializer):
|
|||
model = Note
|
||||
|
||||
|
||||
class ConsumerSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
REST API Nested Serializer for Consumers.
|
||||
return Alias, and the note Associated to it in
|
||||
"""
|
||||
note = serializers.SerializerMethodField()
|
||||
|
||||
email_confirmed = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = Alias
|
||||
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)
|
||||
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):
|
||||
"""
|
||||
REST API Serializer for Transaction templates.
|
||||
|
|
|
@ -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,6 +11,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)
|
||||
|
|
|
@ -10,8 +10,8 @@ from rest_framework.response import Response
|
|||
from rest_framework import status
|
||||
from api.viewsets import ReadProtectedModelViewSet, ReadOnlyProtectedModelViewSet
|
||||
|
||||
from .serializers import NotePolymorphicSerializer, AliasSerializer, TemplateCategorySerializer, \
|
||||
TransactionTemplateSerializer, TransactionPolymorphicSerializer
|
||||
from .serializers import NotePolymorphicSerializer, AliasSerializer, ConsumerSerializer,\
|
||||
TemplateCategorySerializer, TransactionTemplateSerializer, TransactionPolymorphicSerializer
|
||||
from ..models.notes import Note, Alias
|
||||
from ..models.transactions import TransactionTemplate, Transaction, TemplateCategory
|
||||
|
||||
|
@ -90,6 +90,30 @@ 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):
|
||||
"""
|
||||
REST API View set.
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
|
|
|
@ -227,8 +227,7 @@ class RecurrentTransaction(Transaction):
|
|||
|
||||
template = models.ForeignKey(
|
||||
TransactionTemplate,
|
||||
null=True,
|
||||
on_delete=models.SET_NULL,
|
||||
on_delete=models.PROTECT,
|
||||
)
|
||||
category = models.ForeignKey(
|
||||
TemplateCategory,
|
||||
|
|
|
@ -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();',
|
||||
|
@ -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')],
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -107,7 +108,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()
|
||||
|
||||
|
@ -141,9 +142,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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-04-26 00:45+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 <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -205,7 +205,7 @@ 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 ""
|
||||
|
||||
|
@ -245,7 +245,7 @@ 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 ""
|
||||
|
@ -751,7 +751,7 @@ msgstr ""
|
|||
#: apps/note/models/transactions.py:216
|
||||
#: templates/activity/activity_entry.html:13 templates/base.html:84
|
||||
#: templates/note/transaction_form.html:19
|
||||
#: templates/note/transaction_form.html:145
|
||||
#: templates/note/transaction_form.html:140
|
||||
msgid "Transfer"
|
||||
msgstr ""
|
||||
|
||||
|
@ -810,11 +810,11 @@ msgstr ""
|
|||
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 ""
|
||||
|
||||
|
@ -944,7 +944,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 ""
|
||||
|
||||
|
@ -1509,15 +1509,15 @@ 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 ""
|
||||
|
||||
|
@ -1655,31 +1655,36 @@ msgstr ""
|
|||
msgid "There is no 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 ""
|
||||
|
||||
|
@ -1687,53 +1692,67 @@ 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_list.html:9
|
||||
msgid "search button"
|
||||
#: templates/note/transactiontemplate_form.html:21
|
||||
msgid "Price history"
|
||||
msgstr ""
|
||||
|
||||
#: templates/note/transactiontemplate_list.html:13
|
||||
#: 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 ""
|
||||
|
||||
#: 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 ""
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-04-26 00:45+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 <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -206,7 +206,7 @@ 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"
|
||||
|
||||
|
@ -246,7 +246,7 @@ 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"
|
||||
|
@ -759,7 +759,7 @@ msgstr "transactions"
|
|||
#: apps/note/models/transactions.py:216
|
||||
#: templates/activity/activity_entry.html:13 templates/base.html:84
|
||||
#: templates/note/transaction_form.html:19
|
||||
#: templates/note/transaction_form.html:145
|
||||
#: templates/note/transaction_form.html:140
|
||||
msgid "Transfer"
|
||||
msgstr "Virement"
|
||||
|
||||
|
@ -818,11 +818,11 @@ msgstr "Supprimer"
|
|||
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"
|
||||
|
||||
|
@ -965,7 +965,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"
|
||||
|
||||
|
@ -1558,15 +1558,15 @@ 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"
|
||||
|
||||
|
@ -1709,31 +1709,36 @@ msgstr "Sauvegarder les changements"
|
|||
msgid "There is no user with this pattern."
|
||||
msgstr "Il n'y a pas d'utilisateur trouvé 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
|
||||
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"
|
||||
|
||||
|
@ -1741,53 +1746,67 @@ 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
|
||||
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"
|
||||
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 "
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
@ -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;
|
||||
})();
|
||||
|
||||
/**
|
||||
|
@ -79,17 +79,36 @@ function refreshBalance() {
|
|||
* @param fun For each found note with the matched alias `alias`, fun(note, alias) is called.
|
||||
*/
|
||||
function getMatchedNotes(pattern, fun) {
|
||||
$.getJSON("/api/note/alias/?format=json&alias=" + pattern + "&search=user|club|activity&ordering=normalized_name", fun);
|
||||
$.getJSON("/api/note/alias/?format=json&alias=" + pattern + "&search=user|club&ordering=normalized_name", fun);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a <li> entry with a given id and text
|
||||
*/
|
||||
function li(id, text) {
|
||||
return "<li class=\"list-group-item py-1 d-flex justify-content-between align-items-center\"" +
|
||||
" id=\"" + id + "\">" + text + "</li>\n";
|
||||
function li(id, text, extra_css) {
|
||||
return "<li class=\"list-group-item py-1 px-2 d-flex justify-content-between align-items-center text-truncate " + extra_css + "\"" +
|
||||
" id=\"" + id + "\">" + text + "</li>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render note name and picture
|
||||
* @param note The note to render
|
||||
|
@ -97,27 +116,29 @@ function li(id, text) {
|
|||
* @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';
|
||||
$.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;
|
||||
note.user = new_note.user;
|
||||
|
||||
displayNote(note, alias, user_note_field, profile_pic_field);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let img = note.display_image;
|
||||
if (alias !== note.name)
|
||||
if (alias !== note.name && note.name)
|
||||
alias += " (aka. " + note.name + ")";
|
||||
if (user_note_field !== null)
|
||||
$("#" + user_note_field).text(alias + (note.balance == null ? "" : (" : " + pretty_money(note.balance))));
|
||||
if (profile_pic_field != null)
|
||||
$("#" + profile_pic_field).attr('src', img);
|
||||
if (user_note_field !== null) {
|
||||
$("#" + user_note_field).removeAttr('class');
|
||||
$("#" + 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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -132,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) {
|
||||
|
@ -141,12 +162,13 @@ function removeNote(d, note_prefix="note", notes_display, note_list_id, user_not
|
|||
disp.quantity -= disp.id === d.id ? 1 : 0;
|
||||
new_notes_display.push(disp);
|
||||
html += li(note_prefix + "_" + disp.id, disp.name
|
||||
+ "<span class=\"badge badge-dark badge-pill\">" + disp.quantity + "</span>");
|
||||
+ "<span class=\"badge badge-dark badge-pill\">" + disp.quantity + "</span>",
|
||||
displayStyle(disp.note));
|
||||
}
|
||||
});
|
||||
|
||||
notes_display.length = 0;
|
||||
new_notes_display.forEach(function(disp) {
|
||||
new_notes_display.forEach(function (disp) {
|
||||
notes_display.push(disp);
|
||||
});
|
||||
|
||||
|
@ -154,7 +176,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);
|
||||
});
|
||||
|
@ -165,7 +187,6 @@ function removeNote(d, note_prefix="note", notes_display, note_list_id, user_not
|
|||
/**
|
||||
* Generate an auto-complete field to query a note with its alias
|
||||
* @param field_id The identifier of the text field where the alias is typed
|
||||
* @param alias_matched_id The div block identifier where the matched aliases are displayed
|
||||
* @param note_list_id The div block identifier where the notes of the buyers are displayed
|
||||
* @param notes An array containing the note objects of the buyers
|
||||
* @param notes_display An array containing the infos of the buyers: [alias, note id, note object, quantity]
|
||||
|
@ -179,143 +200,145 @@ 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, 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() {
|
||||
|
||||
// Configure tooltip
|
||||
field.tooltip({
|
||||
html: true,
|
||||
placement: 'bottom',
|
||||
title: 'Loading...',
|
||||
trigger: 'manual',
|
||||
container: field.parent()
|
||||
});
|
||||
|
||||
// Clear search on click
|
||||
field.click(function () {
|
||||
field.tooltip('hide');
|
||||
field.val("");
|
||||
});
|
||||
|
||||
let old_pattern = null;
|
||||
|
||||
// When the user type "Enter", the first alias is clicked, and the informations are displayed
|
||||
field.keypress(function(event) {
|
||||
if (event.originalEvent.charCode === 13) {
|
||||
let li_obj = $("#" + alias_matched_id + " li").first();
|
||||
// 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 = field.parent().find("ul 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
|
||||
field.keyup(function(e) {
|
||||
field.keyup(function (e) {
|
||||
if (e.originalEvent.charCode === 13)
|
||||
return;
|
||||
|
||||
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 Alias with note associated
|
||||
if (pattern === "") {
|
||||
field.tooltip('hide');
|
||||
notes.length = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get matched notes with the given pattern
|
||||
getMatchedNotes(pattern, function(aliases) {
|
||||
// The response arrived too late, we stop the request
|
||||
if (pattern !== $("#" + field_id).val())
|
||||
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);
|
||||
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);
|
||||
// Build tooltip content
|
||||
let aliases_matched_html = '<ul class="list-group list-group-flush">';
|
||||
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);
|
||||
});
|
||||
aliases_matched_html += '</ul>';
|
||||
|
||||
// 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
|
||||
var disp = null;
|
||||
notes_display.forEach(function (d) {
|
||||
// We compare the note ids
|
||||
if (d.id === note.id) {
|
||||
d.quantity += 1;
|
||||
disp = d;
|
||||
// Show tooltip
|
||||
field.attr('data-original-title', aliases_matched_html).tooltip('show');
|
||||
|
||||
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 () {
|
||||
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: alias.name,
|
||||
id: note.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
|
||||
+ "<span class=\"badge badge-dark badge-pill\">" + disp.quantity + "</span>");
|
||||
});
|
||||
|
||||
// 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
|
||||
+ "<span class=\"badge badge-dark badge-pill\">"
|
||||
+ disp.quantity + "</span>",
|
||||
displayStyle(disp.note));
|
||||
});
|
||||
|
||||
// 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);
|
||||
|
||||
// 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
|
||||
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));
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// When a validate button is clicked, we switch the validation status
|
||||
function in_validate(id, validated) {
|
||||
|
||||
let invalidity_reason;
|
||||
let reason_obj = $("#invalidity_reason_" + id);
|
||||
|
||||
if (validated)
|
||||
invalidity_reason = reason_obj.val();
|
||||
else
|
||||
invalidity_reason = null;
|
||||
|
||||
$("#validate_" + id).html("<i class='fa fa-spinner'></i>");
|
||||
|
||||
// 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",
|
||||
|
@ -324,19 +347,19 @@ function in_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
|
||||
$(".validate").click(in_validate);
|
||||
$(".validate").click(de_validate);
|
||||
|
||||
refreshBalance();
|
||||
// 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");
|
||||
|
||||
|
|
|
@ -24,13 +24,10 @@ $(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();
|
||||
$("#infos_div").attr('class', 'col-sm-5 col-xl-6');
|
||||
$("#note_infos_div").attr('class', 'col-xl-3');
|
||||
$("#double_conso").click(function() {
|
||||
$("#consos_list_div").removeClass('d-none');
|
||||
$("#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) {
|
||||
|
@ -44,13 +41,10 @@ $(document).ready(function() {
|
|||
}
|
||||
});
|
||||
|
||||
let single_conso_obj = $("#single_conso");
|
||||
single_conso_obj.click(function() {
|
||||
$("#consos_list_div").hide();
|
||||
$("#infos_div").attr('class', 'col-sm-5 col-md-4');
|
||||
$("#note_infos_div").attr('class', 'col-xl-5');
|
||||
$("#single_conso").click(function() {
|
||||
$("#consos_list_div").addClass('d-none');
|
||||
$("#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) {
|
||||
|
@ -69,12 +63,8 @@ $(document).ready(function() {
|
|||
}
|
||||
});
|
||||
|
||||
// Ensure we begin in single consumption. Removing these lines may cause problems when reloading.
|
||||
single_conso_obj.prop('checked', 'true');
|
||||
double_conso_obj.removeAttr('checked');
|
||||
$("label[for='double_conso']").attr('class', 'btn btn-sm btn-outline-primary');
|
||||
|
||||
$("#consos_list_div").hide();
|
||||
// Ensure we begin in single consumption. Fix issue with TurboLinks and BootstrapJS
|
||||
$("label[for='double_conso']").removeClass('active');
|
||||
|
||||
$("#consume_all").click(consumeAll);
|
||||
});
|
||||
|
@ -84,7 +74,7 @@ notes_display = [];
|
|||
buttons = [];
|
||||
|
||||
// When the user searches an alias, we update the auto-completion
|
||||
autoCompleteNote("note", "alias_matched", "note_list", notes, notes_display,
|
||||
autoCompleteNote("note", "note_list", notes, notes_display,
|
||||
"alias", "note", "user_note", "profile_pic", function() {
|
||||
if (buttons.length > 0 && $("#single_conso").is(":checked")) {
|
||||
consumeAll();
|
||||
|
@ -152,7 +142,6 @@ function reset() {
|
|||
notes.length = 0;
|
||||
buttons.length = 0;
|
||||
$("#note_list").html("");
|
||||
$("#alias_matched").html("");
|
||||
$("#consos_list").html("");
|
||||
$("#user_note").text("");
|
||||
$("#profile_pic").attr("src", "/media/pic/default.png");
|
||||
|
@ -167,7 +156,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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,8 +14,6 @@ function reset() {
|
|||
dests.length = 0;
|
||||
$("#source_note_list").html("");
|
||||
$("#dest_note_list").html("");
|
||||
$("#source_alias_matched").html("");
|
||||
$("#dest_alias_matched").html("");
|
||||
$("#amount").val("");
|
||||
$("#reason").val("");
|
||||
$("#last_name").val("");
|
||||
|
@ -28,37 +26,110 @@ function reset() {
|
|||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
autoCompleteNote("source_note", "source_alias_matched", "source_note_list", sources, sources_notes_display,
|
||||
"source_alias", "source_note", "user_note", "profile_pic");
|
||||
autoCompleteNote("dest_note", "dest_alias_matched", "dest_note_list", dests, dests_notes_display,
|
||||
"dest_alias", "dest_note", "user_note", "profile_pic", function() {
|
||||
if ($("#type_credit").is(":checked") || $("#type_debit").is(":checked")) {
|
||||
let last = dests_notes_display[dests_notes_display.length - 1];
|
||||
dests_notes_display.length = 0;
|
||||
dests_notes_display.push(last);
|
||||
/**
|
||||
* If we are in credit/debit mode, check that only one note is entered.
|
||||
* More over, get first name and last name to autocomplete fields.
|
||||
*/
|
||||
function checkUniqueNote() {
|
||||
if ($("#type_credit").is(":checked") || $("#type_debit").is(":checked")) {
|
||||
let arr = $("#type_credit").is(":checked") ? dests_notes_display : sources_notes_display;
|
||||
|
||||
last.quantity = 1;
|
||||
if (arr.length === 0)
|
||||
return;
|
||||
|
||||
if (!last.note.user) {
|
||||
$.getJSON("/api/note/note/" + last.note.id + "/?format=json", function(note) {
|
||||
last.note.user = note.user;
|
||||
$.getJSON("/api/user/" + last.note.user + "/", function(user) {
|
||||
$("#last_name").val(user.last_name);
|
||||
$("#first_name").val(user.first_name);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
let last = arr[arr.length - 1];
|
||||
arr.length = 0;
|
||||
arr.push(last);
|
||||
|
||||
last.quantity = 1;
|
||||
|
||||
if (!last.note.user) {
|
||||
$.getJSON("/api/note/note/" + last.note.id + "/?format=json", function(note) {
|
||||
last.note.user = note.user;
|
||||
$.getJSON("/api/user/" + last.note.user + "/", function(user) {
|
||||
$("#last_name").val(user.last_name);
|
||||
$("#first_name").val(user.first_name);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
$.getJSON("/api/user/" + last.note.user + "/", function(user) {
|
||||
$("#last_name").val(user.last_name);
|
||||
$("#first_name").val(user.first_name);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
autoCompleteNote("source_note", "source_note_list", sources, sources_notes_display,
|
||||
"source_alias", "source_note", "user_note", "profile_pic", checkUniqueNote);
|
||||
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
|
||||
|
@ -91,7 +162,7 @@ $("#btn_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 "
|
||||
|
@ -99,7 +170,7 @@ $("#btn_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,
|
||||
|
@ -111,7 +182,7 @@ $("#btn_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 "
|
||||
|
@ -141,9 +212,9 @@ $("#btn_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 "
|
||||
|
@ -151,7 +222,7 @@ $("#btn_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,
|
||||
|
@ -162,9 +233,9 @@ $("#btn_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 "
|
||||
|
@ -184,10 +255,11 @@ $("#btn_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;
|
||||
let given_reason = $("#reason").val();
|
||||
let source, dest, reason;
|
||||
if ($("#type_credit").is(':checked')) {
|
||||
user_note = dests_notes_display[0].note.id;
|
||||
source = special_note;
|
||||
dest = user_note;
|
||||
reason = "Crédit " + $("#credit_type option:selected").text().toLowerCase();
|
||||
|
@ -195,6 +267,7 @@ $("#btn_transfer").click(function() {
|
|||
reason += " (" + given_reason + ")";
|
||||
}
|
||||
else {
|
||||
user_note = sources_notes_display[0].note.id;
|
||||
source = user_note;
|
||||
dest = special_note;
|
||||
reason = "Retrait " + $("#credit_type option:selected").text().toLowerCase();
|
||||
|
|
|
@ -58,6 +58,20 @@ 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);
|
||||
border: 1px solid rgba(0,0,0,.250);
|
||||
color: #000;
|
||||
margin: 0 .5rem .25rem .5rem;
|
||||
padding: 0;
|
||||
}
|
||||
.bs-tooltip-bottom .arrow::before {
|
||||
border-bottom-color: rgba(0,0,0,.250);
|
||||
}
|
||||
</style>
|
||||
|
||||
{% block extracss %}{% endblock %}
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
<div class="col-sm-5 col-md-4" id="infos_div">
|
||||
<div class="row">
|
||||
{# User details column #}
|
||||
<div class="col-xl-5" id="note_infos_div">
|
||||
<div class="card border-success shadow mb-4">
|
||||
<div class="col">
|
||||
<div class="card border-success shadow mb-4 text-center">
|
||||
<img src="/media/pic/default.png"
|
||||
id="profile_pic" alt="" class="img-fluid rounded mx-auto d-block">
|
||||
id="profile_pic" alt="" class="card-img-top">
|
||||
<div class="card-body text-center">
|
||||
<span id="user_note"></span>
|
||||
</div>
|
||||
|
@ -25,38 +25,45 @@
|
|||
<div class="card border-success shadow mb-4">
|
||||
<div class="card-header">
|
||||
<p class="card-text font-weight-bold">
|
||||
{% trans "Select emitters" %}
|
||||
{% trans "Consum" %}
|
||||
</p>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush" id="note_list">
|
||||
</ul>
|
||||
<div class="card-body">
|
||||
<input class="form-control mx-auto d-block" type="text" id="note" />
|
||||
<ul class="list-group list-group-flush" id="alias_matched">
|
||||
<div class="card-body p-0" style="min-height:125px;">
|
||||
<ul class="list-group list-group-flush" id="note_list">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{# User search with autocompletion #}
|
||||
<div class="card-footer">
|
||||
<input class="form-control mx-auto d-block"
|
||||
placeholder="{% trans "Name or alias..." %}" type="text" id="note" autofocus />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-5" id="consos_list_div">
|
||||
<div class="col-xl-5 d-none" id="consos_list_div">
|
||||
<div class="card border-info shadow mb-4">
|
||||
<div class="card-header">
|
||||
<p class="card-text font-weight-bold">
|
||||
{% trans "Select consumptions" %}
|
||||
</p>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush" id="consos_list">
|
||||
</ul>
|
||||
<button id="consume_all" class="form-control btn btn-primary">
|
||||
{% trans "Consume!" %}
|
||||
</button>
|
||||
<div class="card-body p-0" style="min-height:125px;">
|
||||
<ul class="list-group list-group-flush" id="consos_list">
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-footer text-center">
|
||||
<a id="consume_all" href="#" class="btn btn-primary">
|
||||
{% trans "Consume!" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Buttons column #}
|
||||
<div class="col-sm-7 col-md-8" id="buttons_div">
|
||||
<div class="col">
|
||||
{# Show last used buttons #}
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header">
|
||||
|
@ -123,10 +130,12 @@
|
|||
<div class="btn-group btn-group-toggle float-right" data-toggle="buttons">
|
||||
<label for="single_conso" class="btn btn-sm btn-outline-primary active">
|
||||
<input type="radio" name="conso_type" id="single_conso" checked>
|
||||
<i class="fa fa-long-arrow-left" aria-hidden="true"></i>
|
||||
{% trans "Single consumptions" %}
|
||||
</label>
|
||||
<label for="double_conso" class="btn btn-sm btn-outline-primary">
|
||||
<input type="radio" name="conso_type" id="double_conso">
|
||||
<i class="fa fa-arrows-h" aria-hidden="true"></i>
|
||||
{% trans "Double consumptions" %}
|
||||
</label>
|
||||
</div>
|
||||
|
@ -146,7 +155,7 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block extrajavascript %}
|
||||
<script type="text/javascript" src="/static/js/consos.js"></script>
|
||||
<script type="text/javascript" src="{% static "js/consos.js" %}"></script>
|
||||
<script type="text/javascript">
|
||||
{% for button in most_used %}
|
||||
{% if button.display %}
|
||||
|
|
|
@ -38,8 +38,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-xl-4" id="note_infos_div">
|
||||
<div class="col-md-3" id="note_infos_div">
|
||||
<div class="card border-success shadow mb-4">
|
||||
<img src="/media/pic/default.png"
|
||||
id="profile_pic" alt="" class="img-fluid rounded mx-auto d-block">
|
||||
|
@ -48,7 +47,8 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4" id="emitters_div" style="display: none;">
|
||||
|
||||
<div class="col-md-3" id="emitters_div">
|
||||
<div class="card border-success shadow mb-4">
|
||||
<div class="card-header">
|
||||
<p class="card-text font-weight-bold">
|
||||
|
@ -58,24 +58,53 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||
<ul class="list-group list-group-flush" id="source_note_list">
|
||||
</ul>
|
||||
<div class="card-body">
|
||||
<input class="form-control mx-auto d-block" type="text" id="source_note" />
|
||||
<ul class="list-group list-group-flush" id="source_alias_matched">
|
||||
<input class="form-control mx-auto d-block" type="text" id="source_note" placeholder="{% trans "Name or alias..." %}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3" id="dests_div">
|
||||
<div class="card border-info shadow mb-4">
|
||||
<div class="card-header">
|
||||
<p class="card-text font-weight-bold" id="dest_title">
|
||||
{% trans "Select receivers" %}
|
||||
</p>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush" id="dest_note_list">
|
||||
</ul>
|
||||
<div class="card-body">
|
||||
<input class="form-control mx-auto d-block" type="text" id="dest_note" placeholder="{% trans "Name or alias..." %}" />
|
||||
<ul class="list-group list-group-flush" id="dest_alias_matched">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if "note.notespecial"|not_empty_model_list %}
|
||||
<div class="col-md-4" id="external_div" style="display: none;">
|
||||
<div class="card border-success shadow mb-4">
|
||||
<div class="card-header">
|
||||
<p class="card-text font-weight-bold">
|
||||
{% trans "External payment" %}
|
||||
</p>
|
||||
<div class="col-md-3" id="external_div">
|
||||
<div class="card border-warning shadow mb-4">
|
||||
<div class="card-header">
|
||||
<p class="card-text font-weight-bold">
|
||||
{% trans "Action" %}
|
||||
</p>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush" id="source_note_list">
|
||||
</ul>
|
||||
<div class="card-body">
|
||||
<div class="form-row">
|
||||
<div class="col-md-12">
|
||||
<label for="amount">{% trans "Amount" %} :</label>
|
||||
{% include "note/amount_input.html" with widget=amount_widget %}
|
||||
</div>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush" id="source_note_list">
|
||||
</ul>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="form-row">
|
||||
<div class="col-md-12">
|
||||
<label for="reason">{% trans "Reason" %} :</label>
|
||||
<input class="form-control mx-auto d-block" type="text" id="reason" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-none" id="special_transaction_div">
|
||||
<div class="form-row">
|
||||
<div class="col-md-12">
|
||||
<label for="credit_type">{% trans "Transfer type" %} :</label>
|
||||
|
@ -105,44 +134,14 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="form-row">
|
||||
<div class="col-md-12">
|
||||
<button id="btn_transfer" class="form-control btn btn-primary">{% trans 'Transfer' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="col-md-8" id="dests_div">
|
||||
<div class="card border-info shadow mb-4">
|
||||
<div class="card-header">
|
||||
<p class="card-text font-weight-bold" id="dest_title">
|
||||
{% trans "Select receivers" %}
|
||||
</p>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush" id="dest_note_list">
|
||||
</ul>
|
||||
<div class="card-body">
|
||||
<input class="form-control mx-auto d-block" type="text" id="dest_note" />
|
||||
<ul class="list-group list-group-flush" id="dest_alias_matched">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="amount">{% trans "Amount" %} :</label>
|
||||
{% include "note/amount_input.html" with widget=amount_widget %}
|
||||
</div>
|
||||
|
||||
<div class="form-group col-md-6">
|
||||
<label for="reason">{% trans "Reason" %} :</label>
|
||||
<input class="form-control mx-auto d-block" type="text" id="reason" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="col-md-12">
|
||||
<button id="btn_transfer" class="form-control btn btn-primary">{% trans 'Transfer' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -161,34 +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 }};
|
||||
|
||||
$("#type_gift").click(function() {
|
||||
$("#emitters_div").hide();
|
||||
$("#external_div").hide();
|
||||
$("#dests_div").attr('class', 'col-md-8');
|
||||
$("#dest_title").text("{% trans "Select receivers" %}");
|
||||
});
|
||||
|
||||
$("#type_transfer").click(function() {
|
||||
$("#external_div").hide();
|
||||
$("#emitters_div").show();
|
||||
$("#dests_div").attr('class', 'col-md-4');
|
||||
$("#dest_title").text("{% trans "Select receivers" %}");
|
||||
});
|
||||
|
||||
$("#type_credit").click(function() {
|
||||
$("#emitters_div").hide();
|
||||
$("#external_div").show();
|
||||
$("#dests_div").attr('class', 'col-md-4');
|
||||
$("#dest_title").text("{% trans "Credit note" %}");
|
||||
});
|
||||
|
||||
$("#type_debit").click(function() {
|
||||
$("#emitters_div").hide();
|
||||
$("#external_div").show();
|
||||
$("#dests_div").attr('class', 'col-md-4');
|
||||
$("#dest_title").text("{% trans "Debit note" %}");
|
||||
});
|
||||
username = "{{ user.username }}";
|
||||
</script>
|
||||
<script src="/static/js/transfer.js"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,12 +1,28 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% load pretty_money %}
|
||||
|
||||
{% block content %}
|
||||
<p><a class="btn btn-default" href="{% url 'note:template_list' %}">{% trans "Buttons list" %}</a></p>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{form|crispy}}
|
||||
<button class="btn btn-primary" type="submit">Submit</button>
|
||||
</form>
|
||||
<p>
|
||||
<a class="btn btn-default" href="{% url 'note:template_list' %}">{% trans "Buttons list" %}</a>
|
||||
</p>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{form|crispy}}
|
||||
<button class="btn btn-primary" type="submit">{% trans "Submit" %}</button>
|
||||
</form>
|
||||
|
||||
{% if price_history and price_history.1 %}
|
||||
<hr>
|
||||
|
||||
<h4>{% trans "Price history" %}</h4>
|
||||
<ul>
|
||||
{% for price in price_history %}
|
||||
<li>{{ price.price|pretty_money }} {% if price.time %}({% trans "Obsolete since" %} {{ price.time }}){% else %}({% trans "Current price" %}){% endif %}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -6,9 +6,17 @@
|
|||
<div class="row justify-content-center mb-4">
|
||||
<div class="col-md-10 text-center">
|
||||
<h4>
|
||||
{% trans "search button" %}
|
||||
{% trans "Search button" %}
|
||||
</h4>
|
||||
<input class="form-control mx-auto w-25" type="text" onkeyup="search_field_moved();return(false);" id="search_field"/>
|
||||
<input class="form-control mx-auto w-25" type="text" id="search_field" placeholder="{% trans "Name of the button..." %}">
|
||||
<div class="form-group">
|
||||
<div id="div_active_only" class="form-check">
|
||||
<label for="active_only" class="form-check-label">
|
||||
<input type="checkbox" name="active_only" class="checkboxinput form-check-input" checked="" id="active_only">
|
||||
{% trans "Display visible buttons only" %}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<a class="btn btn-primary text-center my-1" href="{% url 'note:template_create' %}">{% trans "New button" %}</a>
|
||||
</div>
|
||||
|
@ -29,50 +37,65 @@
|
|||
|
||||
{% block extrajavascript %}
|
||||
<script>
|
||||
/* fonction appelée à la fin du timer */
|
||||
function getInfo() {
|
||||
var asked = $("#search_field").val();
|
||||
/* on ne fait la requête que si on a au moins un caractère pour chercher */
|
||||
var sel = $(".table-row");
|
||||
if (asked.length >= 1) {
|
||||
$.getJSON("/api/note/transaction/template/?format=json&search="+asked, function(buttons){
|
||||
let selected_id = buttons.results.map((a => "#row-"+a.id));
|
||||
$(".table-row,"+selected_id.join()).show();
|
||||
$(".table-row").not(selected_id.join()).hide();
|
||||
/* fonction appelée à la fin du timer */
|
||||
function getInfo() {
|
||||
var asked = $("#search_field").val();
|
||||
/* on ne fait la requête que si on a au moins un caractère pour chercher */
|
||||
if (asked.length >= 1) {
|
||||
$.getJSON("/api/note/transaction/template/?format=json&search=" + asked + ($("#active_only").is(":checked") ? "&display=true" : ""), function(buttons) {
|
||||
console.log(buttons);
|
||||
let selected_id = buttons.results.map((a => "#row-" + a.id));
|
||||
console.log(".table-row " + selected_id.join());
|
||||
$(".table-row " + selected_id.join()).removeClass('d-none');
|
||||
$(".table-row").not(selected_id.join()).addClass('d-none');
|
||||
});
|
||||
}
|
||||
else {
|
||||
if ($("#active_only").is(":checked")) {
|
||||
$('.table-success').removeClass('d-none');
|
||||
$('.table-danger').addClass('d-none');
|
||||
}
|
||||
else {
|
||||
// show everything
|
||||
$('table tr').removeClass('d-none');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}else{
|
||||
// show everything
|
||||
$('table tr').show();
|
||||
var timer;
|
||||
var timer_on;
|
||||
/* Fontion appelée quand le texte change (délenche le timer) */
|
||||
function search_field_moved() {
|
||||
if (timer_on) { // Si le timer a déjà été lancé, on réinitialise le compteur.
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(getInfo, 300);
|
||||
}
|
||||
else { // Sinon, on le lance et on enregistre le fait qu'il tourne.
|
||||
timer = setTimeout(getInfo, 300);
|
||||
timer_on = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
var timer;
|
||||
var timer_on;
|
||||
/* Fontion appelée quand le texte change (délenche le timer) */
|
||||
function search_field_moved(secondfield) {
|
||||
if (timer_on) { // Si le timer a déjà été lancé, on réinitialise le compteur.
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout("getInfo(" + secondfield + ")", 300);
|
||||
}
|
||||
else { // Sinon, on le lance et on enregistre le fait qu'il tourne.
|
||||
timer = setTimeout("getInfo(" + secondfield + ")", 300);
|
||||
timer_on = true;
|
||||
}
|
||||
}
|
||||
// on click of button "delete" , call the API
|
||||
function delete_button(button_id){
|
||||
$.ajax({
|
||||
url:"/api/note/transaction/template/"+button_id+"/",
|
||||
method:"DELETE",
|
||||
headers: {"X-CSRFTOKEN": CSRF_TOKEN}
|
||||
})
|
||||
.done(function(){
|
||||
addMsg('{% trans "button successfully deleted "%}','success');
|
||||
$("#buttons_table").load("{% url 'note:template_list' %} #buttons_table");
|
||||
})
|
||||
.fail(function(){
|
||||
addMsg(' {% trans "Unable to delete button "%} #' + button_id,'danger' )
|
||||
});
|
||||
}
|
||||
// on click of button "delete" , call the API
|
||||
function delete_button(button_id) {
|
||||
$.ajax({
|
||||
url:"/api/note/transaction/template/"+button_id+"/",
|
||||
method:"DELETE",
|
||||
headers: {"X-CSRFTOKEN": CSRF_TOKEN}
|
||||
})
|
||||
.done(function(){
|
||||
addMsg('{% trans "button successfully deleted "%}','success');
|
||||
$("#buttons_table").load("{% url 'note:template_list' %} #buttons_table");
|
||||
})
|
||||
.fail(function(){
|
||||
addMsg(' {% trans "Unable to delete button "%} #' + button_id,'danger' )
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
$("#search_field").keyup(search_field_moved);
|
||||
$("#active_only").change(search_field_moved);
|
||||
|
||||
search_field_moved();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
Loading…
Reference in New Issue