Add "search transactions page"

This commit is contained in:
Yohann D'ANELLO 2020-08-03 18:49:15 +02:00
parent 55580bc11e
commit 985a5ca876
15 changed files with 455 additions and 196 deletions

View File

@ -3,10 +3,11 @@
from django import forms
from django.contrib.contenttypes.models import ContentType
from django.forms import CheckboxSelectMultiple
from django.utils.translation import gettext_lazy as _
from note_kfet.inputs import Autocomplete, AmountInput
from note_kfet.inputs import Autocomplete, AmountInput, DateTimePickerInput
from .models import TransactionTemplate, NoteClub
from .models import TransactionTemplate, NoteClub, Alias
class ImageForm(forms.Form):
@ -38,3 +39,80 @@ class TransactionTemplateForm(forms.ModelForm):
),
'amount': AmountInput(),
}
class SearchTransactionForm(forms.Form):
source = forms.ModelChoiceField(
queryset=Alias.objects.all(),
label=_("Source"),
required=False,
widget=Autocomplete(
Alias,
resetable=True,
attrs={
'api_url': '/api/note/alias/',
'placeholder': 'Note ...',
},
),
)
destination = forms.ModelChoiceField(
queryset=Alias.objects.all(),
label=_("Destination"),
required=False,
widget=Autocomplete(
Alias,
resetable=True,
attrs={
'api_url': '/api/note/alias/',
'placeholder': 'Note ...',
},
),
)
type = forms.ModelMultipleChoiceField(
queryset=ContentType.objects.filter(app_label="note", model__endswith="transaction"),
initial=ContentType.objects.filter(app_label="note", model__endswith="transaction"),
label=_("Type"),
required=False,
widget=CheckboxSelectMultiple(),
)
reason = forms.CharField(
label=_("Reason"),
required=False,
)
valid = forms.BooleanField(
label=_("Valid"),
initial=False,
required=False,
)
amount_gte = forms.Field(
label=_("Total amount greater than"),
initial=0,
required=False,
widget=AmountInput(),
)
amount_lte = forms.Field(
initial=2 ** 31 - 1,
label=_("Total amount less than"),
required=False,
widget=AmountInput(),
)
created_after = forms.Field(
label=_("Created after"),
initial="2000-01-01 00:00",
required=False,
widget=DateTimePickerInput(),
)
created_before = forms.Field(
label=_("Created before"),
initial="2042-12-31 21:42",
required=False,
widget=DateTimePickerInput(),
)

View File

@ -243,6 +243,7 @@ class RecurrentTransaction(Transaction):
TransactionTemplate,
on_delete=models.PROTECT,
)
category = models.ForeignKey(
TemplateCategory,
on_delete=models.PROTECT,
@ -252,6 +253,10 @@ class RecurrentTransaction(Transaction):
def type(self):
return _('Template')
class Meta:
verbose_name = _("recurrent transaction")
verbose_name_plural = _("recurrent transactions")
class SpecialTransaction(Transaction):
"""
@ -290,6 +295,10 @@ class SpecialTransaction(Transaction):
raise(ValidationError(_("A special transaction is only possible between a"
" Note associated to a payment method and a User or a Club")))
class Meta:
verbose_name = _("Special transaction")
verbose_name_plural = _("Special transactions")
class MembershipTransaction(Transaction):
"""

View File

@ -12,4 +12,5 @@ urlpatterns = [
path('buttons/update/<int:pk>/', views.TransactionTemplateUpdateView.as_view(), name='template_update'),
path('buttons/', views.TransactionTemplateListView.as_view(), name='template_list'),
path('consos/', views.ConsoView.as_view(), name='consos'),
path('transactions/<int:pk>/', views.TransactionSearchView.as_view(), name='transactions'),
]

View File

@ -5,9 +5,9 @@ import json
from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
from django.db.models import Q, F
from django.utils.translation import gettext_lazy as _
from django.views.generic import CreateView, UpdateView
from django.views.generic import CreateView, UpdateView, DetailView
from django_tables2 import SingleTableView
from django.urls import reverse_lazy
@ -16,8 +16,8 @@ from note_kfet.inputs import AmountInput
from permission.backends import PermissionBackend
from permission.views import ProtectQuerysetMixin
from .forms import TransactionTemplateForm
from .models import TemplateCategory, Transaction, TransactionTemplate, RecurrentTransaction, NoteSpecial
from .forms import TransactionTemplateForm, SearchTransactionForm
from .models import TemplateCategory, Transaction, TransactionTemplate, RecurrentTransaction, NoteSpecial, Note
from .models.transactions import SpecialTransaction
from .tables import HistoryTable, ButtonTable
@ -171,3 +171,51 @@ class ConsoView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
context['no_cache'] = True
return context
class TransactionSearchView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
model = Note
context_object_name = "note"
template_name = "note/search_transactions.html"
extra_context = {"title": _("Search transactions")}
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
form = SearchTransactionForm(data=self.request.GET if self.request.GET else None)
context["form"] = form
form.full_clean()
if form.is_valid():
data = form.cleaned_data
else:
data = {}
transactions = Transaction.objects.annotate(total_amount=F("quantity") * F("amount")).filter(
PermissionBackend.filter_queryset(self.request.user, Transaction, "view"))\
.filter(Q(source=self.object) | Q(destination=self.object)).order_by('-created_at')
if "source" in data and data["source"]:
transactions = transactions.filter(source_id=data["source"].note_id)
if "destination" in data and data["destination"]:
transactions = transactions.filter(destination_id=data["destination"].note_id)
if "type" in data and data["type"]:
transactions = transactions.filter(polymorphic_ctype__in=data["type"])
if "reason" in data and data["reason"]:
transactions = transactions.filter(reason__iregex=data["reason"])
if "valid" in data and data["valid"]:
transactions = transactions.filter(valid=data["valid"])
if "amount_gte" in data and data["amount_gte"]:
transactions = transactions.filter(total_amount__gte=data["amount_gte"])
if "amount_lte" in data and data["amount_lte"]:
transactions = transactions.filter(total_amount__lte=data["amount_lte"])
if "created_after" in data and data["created_after"]:
transactions = transactions.filter(created_at__gte=data["created_after"])
if "created_before" in data and data["created_before"]:
transactions = transactions.filter(created_at__lte=data["created_before"])
table = HistoryTable(transactions)
table.paginate(per_page=20)
context["table"] = table
return context

View File

@ -130,7 +130,7 @@ class WEIDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
context["my_registration"] = my_registration
buses = Bus.objects.filter(PermissionBackend.filter_queryset(self.request.user, Bus, "view")) \
.filter(wei=self.object).annotate(count=Count("memberships"))
.filter(wei=self.object).annotate(count=Count("memberships")).order_by("name")
bus_table = BusTable(data=buses, prefix="bus-")
context['buses'] = bus_table
@ -589,9 +589,6 @@ class WEIUpdateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Update
form_class = WEIRegistrationForm
extra_context = {"title": _("Update WEI Registration")}
def get_queryset(self, **kwargs):
return WEIRegistration.objects
def dispatch(self, request, *args, **kwargs):
wei = self.get_object().wei
today = date.today()

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-08-03 12:35+0200\n"
"POT-Creation-Date: 2020-08-03 18:38+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"
@ -46,7 +46,7 @@ msgstr ""
#: apps/activity/models.py:24 apps/activity/models.py:49
#: apps/member/models.py:158 apps/note/models/notes.py:212
#: apps/note/models/transactions.py:25 apps/note/models/transactions.py:45
#: apps/note/models/transactions.py:263 apps/permission/models.py:339
#: apps/note/models/transactions.py:268 apps/permission/models.py:339
#: apps/wei/models.py:65 apps/wei/models.py:117
#: templates/member/club_info.html:13 templates/member/profile_info.html:14
#: templates/registration/future_profile_detail.html:16
@ -182,16 +182,16 @@ msgstr ""
msgid "remove"
msgstr ""
#: apps/activity/tables.py:75 apps/treasury/models.py:141
#: apps/activity/tables.py:75 apps/note/forms.py:76 apps/treasury/models.py:141
msgid "Type"
msgstr ""
#: apps/activity/tables.py:77 apps/member/forms.py:102
#: apps/activity/tables.py:77 apps/member/forms.py:103
#: apps/registration/forms.py:70 apps/treasury/forms.py:120
msgid "Last name"
msgstr ""
#: apps/activity/tables.py:79 apps/member/forms.py:107
#: apps/activity/tables.py:79 apps/member/forms.py:108
#: apps/registration/forms.py:75 apps/treasury/forms.py:122
#: templates/note/transaction_form.html:129
msgid "First name"
@ -225,7 +225,7 @@ msgstr ""
msgid "Invite guest to the activity \"{}\""
msgstr ""
#: apps/activity/views.py:171
#: apps/activity/views.py:181
msgid "Entry for activity \"{}\""
msgstr ""
@ -313,45 +313,45 @@ msgstr ""
msgid "member"
msgstr ""
#: apps/member/forms.py:58 apps/member/views.py:82
#: apps/member/forms.py:59 apps/member/views.py:82
#: apps/registration/forms.py:28
msgid "An alias with a similar name already exists."
msgstr ""
#: apps/member/forms.py:81 apps/registration/forms.py:50
#: apps/member/forms.py:82 apps/registration/forms.py:50
msgid "Inscription paid by Société Générale"
msgstr ""
#: apps/member/forms.py:83 apps/registration/forms.py:52
#: apps/member/forms.py:84 apps/registration/forms.py:52
msgid "Check this case is the Société Générale paid the inscription."
msgstr ""
#: apps/member/forms.py:88 apps/registration/forms.py:57
#: apps/member/forms.py:89 apps/registration/forms.py:57
msgid "Credit type"
msgstr ""
#: apps/member/forms.py:89 apps/registration/forms.py:58
#: apps/member/forms.py:90 apps/registration/forms.py:58
msgid "No credit"
msgstr ""
#: apps/member/forms.py:91
#: apps/member/forms.py:92
msgid "You can credit the note of the user."
msgstr ""
#: apps/member/forms.py:95 apps/registration/forms.py:63
#: apps/member/forms.py:96 apps/registration/forms.py:63
msgid "Credit amount"
msgstr ""
#: apps/member/forms.py:112 apps/registration/forms.py:80
#: apps/member/forms.py:113 apps/registration/forms.py:80
#: apps/treasury/forms.py:124 templates/note/transaction_form.html:135
msgid "Bank"
msgstr ""
#: apps/member/forms.py:139
#: apps/member/forms.py:140
msgid "User"
msgstr ""
#: apps/member/forms.py:153
#: apps/member/forms.py:154
msgid "Roles"
msgstr ""
@ -540,7 +540,7 @@ msgstr ""
msgid "membership ends on"
msgstr ""
#: apps/member/models.py:310 apps/member/views.py:535 apps/wei/views.py:795
#: apps/member/models.py:310 apps/member/views.py:535 apps/wei/views.py:793
msgid "User is not a member of the parent club"
msgstr ""
@ -620,7 +620,7 @@ msgstr ""
msgid "Add new member to the club"
msgstr ""
#: apps/member/views.py:530 apps/wei/views.py:786
#: apps/member/views.py:530 apps/wei/views.py:784
msgid ""
"This user don't have enough money to join this club, and can't have a "
"negative balance."
@ -662,14 +662,46 @@ msgstr ""
msgid "amount"
msgstr ""
#: apps/note/forms.py:14
#: apps/note/forms.py:15
msgid "select an image"
msgstr ""
#: apps/note/forms.py:15
#: apps/note/forms.py:16
msgid "Maximal size: 2MB"
msgstr ""
#: apps/note/forms.py:47
msgid "Source"
msgstr ""
#: apps/note/forms.py:61
msgid "Destination"
msgstr ""
#: apps/note/forms.py:82 templates/note/transaction_form.html:104
msgid "Reason"
msgstr ""
#: apps/note/forms.py:87 apps/treasury/tables.py:117
msgid "Valid"
msgstr ""
#: apps/note/forms.py:93
msgid "Total amount greater than"
msgstr ""
#: apps/note/forms.py:101
msgid "Total amount less than"
msgstr ""
#: apps/note/forms.py:107
msgid "Created after"
msgstr ""
#: apps/note/forms.py:114
msgid "Created before"
msgstr ""
#: apps/note/models/notes.py:29
msgid "account balance"
msgstr ""
@ -842,39 +874,55 @@ msgstr ""
msgid "Transfer"
msgstr ""
#: apps/note/models/transactions.py:253
#: apps/note/models/transactions.py:254
msgid "Template"
msgstr ""
#: apps/note/models/transactions.py:268
msgid "first_name"
#: apps/note/models/transactions.py:257
msgid "recurrent transaction"
msgstr ""
#: apps/note/models/transactions.py:258
msgid "recurrent transactions"
msgstr ""
#: apps/note/models/transactions.py:273
msgid "first_name"
msgstr ""
#: apps/note/models/transactions.py:278
msgid "bank"
msgstr ""
#: apps/note/models/transactions.py:279
#: apps/note/models/transactions.py:284
#: templates/activity/activity_entry.html:17
#: templates/note/transaction_form.html:20
msgid "Credit"
msgstr ""
#: apps/note/models/transactions.py:279 templates/note/transaction_form.html:24
#: apps/note/models/transactions.py:284 templates/note/transaction_form.html:24
msgid "Debit"
msgstr ""
#: apps/note/models/transactions.py:290
#: apps/note/models/transactions.py:295
msgid ""
"A special transaction is only possible between a Note associated to a "
"payment method and a User or a Club"
msgstr ""
#: apps/note/models/transactions.py:307 apps/note/models/transactions.py:312
#: apps/note/models/transactions.py:299
msgid "Special transaction"
msgstr ""
#: apps/note/models/transactions.py:300
msgid "Special transactions"
msgstr ""
#: apps/note/models/transactions.py:316 apps/note/models/transactions.py:321
msgid "membership transaction"
msgstr ""
#: apps/note/models/transactions.py:308 apps/treasury/models.py:228
#: apps/note/models/transactions.py:317 apps/treasury/models.py:228
msgid "membership transactions"
msgstr ""
@ -903,26 +951,30 @@ msgstr ""
msgid "Edit"
msgstr ""
#: apps/note/views.py:33
#: apps/note/views.py:35
msgid "Transfer money"
msgstr ""
#: apps/note/views.py:69
#: apps/note/views.py:75
msgid "Create new button"
msgstr ""
#: apps/note/views.py:78
#: apps/note/views.py:84
msgid "Search button"
msgstr ""
#: apps/note/views.py:101
#: apps/note/views.py:107
msgid "Update button"
msgstr ""
#: apps/note/views.py:138 templates/base.html:94
#: apps/note/views.py:144 templates/base.html:94
msgid "Consumptions"
msgstr ""
#: apps/note/views.py:180
msgid "Search transactions"
msgstr ""
#: apps/permission/models.py:99
#, python-brace-format
msgid "Can {type} {model}.{field} in {query}"
@ -1288,10 +1340,6 @@ msgstr ""
msgid "Remove"
msgstr ""
#: apps/treasury/tables.py:117
msgid "Valid"
msgstr ""
#: apps/treasury/tables.py:124
msgid "Yes"
msgstr ""
@ -1342,37 +1390,37 @@ msgstr ""
msgid "WEI"
msgstr ""
#: apps/wei/forms/registration.py:47 apps/wei/models.py:112
#: apps/wei/forms/registration.py:48 apps/wei/models.py:112
#: apps/wei/models.py:297
msgid "bus"
msgstr ""
#: apps/wei/forms/registration.py:48
#: apps/wei/forms/registration.py:49
msgid ""
"This choice is not definitive. The WEI organizers are free to attribute for "
"you a bus and a team, in particular if you are a free eletron."
msgstr ""
#: apps/wei/forms/registration.py:54
#: apps/wei/forms/registration.py:56
msgid "Team"
msgstr ""
#: apps/wei/forms/registration.py:56
#: apps/wei/forms/registration.py:58
msgid ""
"Leave this field empty if you won't be in a team (staff, bus chief, free "
"electron)"
msgstr ""
#: apps/wei/forms/registration.py:61 apps/wei/forms/registration.py:67
#: apps/wei/forms/registration.py:64 apps/wei/forms/registration.py:74
#: apps/wei/models.py:147
msgid "WEI Roles"
msgstr ""
#: apps/wei/forms/registration.py:62
#: apps/wei/forms/registration.py:65
msgid "Select the roles that you are interested in."
msgstr ""
#: apps/wei/forms/registration.py:72
#: apps/wei/forms/registration.py:81
msgid "This team doesn't belong to the given bus."
msgstr ""
@ -1618,7 +1666,7 @@ msgstr ""
msgid "Register 1A"
msgstr ""
#: apps/wei/views.py:489 apps/wei/views.py:559
#: apps/wei/views.py:489 apps/wei/views.py:560
msgid "This user is already registered to this WEI."
msgstr ""
@ -1636,31 +1684,31 @@ msgstr ""
msgid "Register 2A+"
msgstr ""
#: apps/wei/views.py:541 apps/wei/views.py:629
#: apps/wei/views.py:542 apps/wei/views.py:627
msgid "You already opened an account in the Société générale."
msgstr ""
#: apps/wei/views.py:589
#: apps/wei/views.py:590
msgid "Update WEI Registration"
msgstr ""
#: apps/wei/views.py:679
#: apps/wei/views.py:677
msgid "Delete WEI registration"
msgstr ""
#: apps/wei/views.py:690
#: apps/wei/views.py:688
msgid "You don't have the right to delete this WEI registration."
msgstr ""
#: apps/wei/views.py:709
#: apps/wei/views.py:707
msgid "Validate WEI registration"
msgstr ""
#: apps/wei/views.py:790
#: apps/wei/views.py:788
msgid "This user didn't give her/his caution check."
msgstr ""
#: apps/wei/views.py:827 apps/wei/views.py:880 apps/wei/views.py:890
#: apps/wei/views.py:825 apps/wei/views.py:878 apps/wei/views.py:888
#: templates/wei/survey.html:12 templates/wei/survey_closed.html:12
#: templates/wei/survey_end.html:12
msgid "Survey WEI"
@ -1822,6 +1870,10 @@ msgstr ""
msgid "Add alias"
msgstr ""
#: templates/member/autocomplete_model.html:11
msgid "Reset"
msgstr ""
#: templates/member/club_info.html:17
msgid "Club Parent"
msgstr ""
@ -1990,10 +2042,6 @@ msgstr ""
msgid "Action"
msgstr ""
#: templates/note/transaction_form.html:104
msgid "Reason"
msgstr ""
#: templates/note/transaction_form.html:113
msgid "Transfer type"
msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-08-03 12:35+0200\n"
"POT-Creation-Date: 2020-08-03 18:38+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"
@ -47,7 +47,7 @@ msgstr "Vous ne pouvez pas inviter plus de 3 personnes à cette activité."
#: apps/activity/models.py:24 apps/activity/models.py:49
#: apps/member/models.py:158 apps/note/models/notes.py:212
#: apps/note/models/transactions.py:25 apps/note/models/transactions.py:45
#: apps/note/models/transactions.py:263 apps/permission/models.py:339
#: apps/note/models/transactions.py:268 apps/permission/models.py:339
#: apps/wei/models.py:65 apps/wei/models.py:117
#: templates/member/club_info.html:13 templates/member/profile_info.html:14
#: templates/registration/future_profile_detail.html:16
@ -183,16 +183,16 @@ msgstr "Entré le "
msgid "remove"
msgstr "supprimer"
#: apps/activity/tables.py:75 apps/treasury/models.py:141
#: apps/activity/tables.py:75 apps/note/forms.py:76 apps/treasury/models.py:141
msgid "Type"
msgstr "Type"
#: apps/activity/tables.py:77 apps/member/forms.py:102
#: apps/activity/tables.py:77 apps/member/forms.py:103
#: apps/registration/forms.py:70 apps/treasury/forms.py:120
msgid "Last name"
msgstr "Nom de famille"
#: apps/activity/tables.py:79 apps/member/forms.py:107
#: apps/activity/tables.py:79 apps/member/forms.py:108
#: apps/registration/forms.py:75 apps/treasury/forms.py:122
#: templates/note/transaction_form.html:129
msgid "First name"
@ -226,7 +226,7 @@ msgstr "Modifier l'activité"
msgid "Invite guest to the activity \"{}\""
msgstr "Invitation pour l'activité « {} »"
#: apps/activity/views.py:171
#: apps/activity/views.py:181
msgid "Entry for activity \"{}\""
msgstr "Entrées pour l'activité « {} »"
@ -314,45 +314,45 @@ msgstr "cotisation"
msgid "member"
msgstr "adhérent"
#: apps/member/forms.py:58 apps/member/views.py:82
#: apps/member/forms.py:59 apps/member/views.py:82
#: apps/registration/forms.py:28
msgid "An alias with a similar name already exists."
msgstr "Un alias avec un nom similaire existe déjà."
#: apps/member/forms.py:81 apps/registration/forms.py:50
#: apps/member/forms.py:82 apps/registration/forms.py:50
msgid "Inscription paid by Société Générale"
msgstr "Inscription payée par la Société générale"
#: apps/member/forms.py:83 apps/registration/forms.py:52
#: apps/member/forms.py:84 apps/registration/forms.py:52
msgid "Check this case is the Société Générale paid the inscription."
msgstr "Cochez cette case si la Société Générale a payé l'inscription."
#: apps/member/forms.py:88 apps/registration/forms.py:57
#: apps/member/forms.py:89 apps/registration/forms.py:57
msgid "Credit type"
msgstr "Type de rechargement"
#: apps/member/forms.py:89 apps/registration/forms.py:58
#: apps/member/forms.py:90 apps/registration/forms.py:58
msgid "No credit"
msgstr "Pas de rechargement"
#: apps/member/forms.py:91
#: apps/member/forms.py:92
msgid "You can credit the note of the user."
msgstr "Vous pouvez créditer la note de l'utisateur avant l'adhésion."
#: apps/member/forms.py:95 apps/registration/forms.py:63
#: apps/member/forms.py:96 apps/registration/forms.py:63
msgid "Credit amount"
msgstr "Montant à créditer"
#: apps/member/forms.py:112 apps/registration/forms.py:80
#: apps/member/forms.py:113 apps/registration/forms.py:80
#: apps/treasury/forms.py:124 templates/note/transaction_form.html:135
msgid "Bank"
msgstr "Banque"
#: apps/member/forms.py:139
#: apps/member/forms.py:140
msgid "User"
msgstr "Utilisateur"
#: apps/member/forms.py:153
#: apps/member/forms.py:154
msgid "Roles"
msgstr "Rôles"
@ -545,7 +545,7 @@ msgstr "l'adhésion commence le"
msgid "membership ends on"
msgstr "l'adhésion finit le"
#: apps/member/models.py:310 apps/member/views.py:535 apps/wei/views.py:795
#: apps/member/models.py:310 apps/member/views.py:535 apps/wei/views.py:793
msgid "User is not a member of the parent club"
msgstr "L'utilisateur n'est pas membre du club parent"
@ -625,7 +625,7 @@ msgstr "Modifier le club"
msgid "Add new member to the club"
msgstr "Ajouter un nouveau membre au club"
#: apps/member/views.py:530 apps/wei/views.py:786
#: apps/member/views.py:530 apps/wei/views.py:784
msgid ""
"This user don't have enough money to join this club, and can't have a "
"negative balance."
@ -669,14 +669,46 @@ msgstr "destination"
msgid "amount"
msgstr "montant"
#: apps/note/forms.py:14
#: apps/note/forms.py:15
msgid "select an image"
msgstr "Choisissez une image"
#: apps/note/forms.py:15
#: apps/note/forms.py:16
msgid "Maximal size: 2MB"
msgstr "Taille maximale : 2 Mo"
#: apps/note/forms.py:47
msgid "Source"
msgstr "Source"
#: apps/note/forms.py:61
msgid "Destination"
msgstr "Destination"
#: apps/note/forms.py:82 templates/note/transaction_form.html:104
msgid "Reason"
msgstr "Raison"
#: apps/note/forms.py:87 apps/treasury/tables.py:117
msgid "Valid"
msgstr "Valide"
#: apps/note/forms.py:93
msgid "Total amount greater than"
msgstr "Montant total supérieur à"
#: apps/note/forms.py:101
msgid "Total amount less than"
msgstr "Montant total inférieur à"
#: apps/note/forms.py:107
msgid "Created after"
msgstr "Créé après"
#: apps/note/forms.py:114
msgid "Created before"
msgstr "Créé avant"
#: apps/note/models/notes.py:29
msgid "account balance"
msgstr "solde du compte"
@ -805,11 +837,11 @@ msgstr "mis en avant"
#: apps/note/models/transactions.py:87
msgid "transaction template"
msgstr "modèle de transaction"
msgstr "Modèle de transaction"
#: apps/note/models/transactions.py:88
msgid "transaction templates"
msgstr "modèles de transaction"
msgstr "Modèles de transaction"
#: apps/note/models/transactions.py:112 apps/note/models/transactions.py:125
#: apps/note/tables.py:35 apps/note/tables.py:44
@ -830,12 +862,12 @@ msgstr "Motif d'invalidité"
#: apps/note/models/transactions.py:159
msgid "transaction"
msgstr "transaction"
msgstr "Transaction"
#: apps/note/models/transactions.py:160
#: templates/treasury/sogecredit_detail.html:22
msgid "transactions"
msgstr "transactions"
msgstr "Transactions"
#: apps/note/models/transactions.py:175
msgid ""
@ -852,29 +884,37 @@ msgstr ""
msgid "Transfer"
msgstr "Virement"
#: apps/note/models/transactions.py:253
#: apps/note/models/transactions.py:254
msgid "Template"
msgstr "Bouton"
#: apps/note/models/transactions.py:268
#: apps/note/models/transactions.py:257
msgid "recurrent transaction"
msgstr "Transaction issue de bouton"
#: apps/note/models/transactions.py:258
msgid "recurrent transactions"
msgstr "Transactions issues de boutons"
#: apps/note/models/transactions.py:273
msgid "first_name"
msgstr "prénom"
#: apps/note/models/transactions.py:273
#: apps/note/models/transactions.py:278
msgid "bank"
msgstr "banque"
#: apps/note/models/transactions.py:279
#: apps/note/models/transactions.py:284
#: templates/activity/activity_entry.html:17
#: templates/note/transaction_form.html:20
msgid "Credit"
msgstr "Crédit"
#: apps/note/models/transactions.py:279 templates/note/transaction_form.html:24
#: apps/note/models/transactions.py:284 templates/note/transaction_form.html:24
msgid "Debit"
msgstr "Débit"
#: apps/note/models/transactions.py:290
#: apps/note/models/transactions.py:295
msgid ""
"A special transaction is only possible between a Note associated to a "
"payment method and a User or a Club"
@ -882,11 +922,19 @@ msgstr ""
"Une transaction spéciale n'est possible que entre une note associée à un "
"mode de paiement et un utilisateur ou un club."
#: apps/note/models/transactions.py:307 apps/note/models/transactions.py:312
#: apps/note/models/transactions.py:299
msgid "Special transaction"
msgstr "Transaction de crédit/retrait"
#: apps/note/models/transactions.py:300
msgid "Special transactions"
msgstr "Transactions de crédit/retrait"
#: apps/note/models/transactions.py:316 apps/note/models/transactions.py:321
msgid "membership transaction"
msgstr "Transaction d'adhésion"
#: apps/note/models/transactions.py:308 apps/treasury/models.py:228
#: apps/note/models/transactions.py:317 apps/treasury/models.py:228
msgid "membership transactions"
msgstr "Transactions d'adhésion"
@ -915,26 +963,30 @@ msgstr "Supprimer"
msgid "Edit"
msgstr "Éditer"
#: apps/note/views.py:33
#: apps/note/views.py:35
msgid "Transfer money"
msgstr "Transférer de l'argent"
#: apps/note/views.py:69
#: apps/note/views.py:75
msgid "Create new button"
msgstr "Créer un nouveau bouton"
#: apps/note/views.py:78
#: apps/note/views.py:84
msgid "Search button"
msgstr "Chercher un bouton"
#: apps/note/views.py:101
#: apps/note/views.py:107
msgid "Update button"
msgstr "Modifier le bouton"
#: apps/note/views.py:138 templates/base.html:94
#: apps/note/views.py:144 templates/base.html:94
msgid "Consumptions"
msgstr "Consommations"
#: apps/note/views.py:180
msgid "Search transactions"
msgstr "Rechercher des transactions"
#: apps/permission/models.py:99
#, python-brace-format
msgid "Can {type} {model}.{field} in {query}"
@ -1317,10 +1369,6 @@ msgstr "Ajouter"
msgid "Remove"
msgstr "supprimer"
#: apps/treasury/tables.py:117
msgid "Valid"
msgstr "Valide"
#: apps/treasury/tables.py:124
msgid "Yes"
msgstr "Oui"
@ -1371,12 +1419,12 @@ msgstr "Gérer les crédits de la Société générale"
msgid "WEI"
msgstr "WEI"
#: apps/wei/forms/registration.py:47 apps/wei/models.py:112
#: apps/wei/forms/registration.py:48 apps/wei/models.py:112
#: apps/wei/models.py:297
msgid "bus"
msgstr "Bus"
#: apps/wei/forms/registration.py:48
#: apps/wei/forms/registration.py:49
msgid ""
"This choice is not definitive. The WEI organizers are free to attribute for "
"you a bus and a team, in particular if you are a free eletron."
@ -1385,11 +1433,11 @@ msgstr ""
"attribuer un bus et une équipe, en particulier si vous êtes un électron "
"libre."
#: apps/wei/forms/registration.py:54
#: apps/wei/forms/registration.py:56
msgid "Team"
msgstr "Équipe"
#: apps/wei/forms/registration.py:56
#: apps/wei/forms/registration.py:58
msgid ""
"Leave this field empty if you won't be in a team (staff, bus chief, free "
"electron)"
@ -1397,16 +1445,16 @@ msgstr ""
"Laissez ce champ vide si vous ne serez pas dans une équipe (staff, chef de "
"bus ou électron libre)"
#: apps/wei/forms/registration.py:61 apps/wei/forms/registration.py:67
#: apps/wei/forms/registration.py:64 apps/wei/forms/registration.py:74
#: apps/wei/models.py:147
msgid "WEI Roles"
msgstr "Rôles au WEI"
#: apps/wei/forms/registration.py:62
#: apps/wei/forms/registration.py:65
msgid "Select the roles that you are interested in."
msgstr "Sélectionnez les rôles qui vous intéressent."
#: apps/wei/forms/registration.py:72
#: apps/wei/forms/registration.py:81
msgid "This team doesn't belong to the given bus."
msgstr "Cette équipe n'appartient pas à ce bus."
@ -1662,7 +1710,7 @@ msgstr "Inscrire un 1A au WEI"
msgid "Register 1A"
msgstr "Inscrire un 1A"
#: apps/wei/views.py:489 apps/wei/views.py:559
#: apps/wei/views.py:489 apps/wei/views.py:560
msgid "This user is already registered to this WEI."
msgstr "Cette personne est déjà inscrite au WEI."
@ -1682,31 +1730,31 @@ msgstr "Inscrire un 2A+ au WEI"
msgid "Register 2A+"
msgstr "Inscrire un 2A+"
#: apps/wei/views.py:541 apps/wei/views.py:629
#: apps/wei/views.py:542 apps/wei/views.py:627
msgid "You already opened an account in the Société générale."
msgstr "Vous avez déjà ouvert un compte auprès de la société générale."
#: apps/wei/views.py:589
#: apps/wei/views.py:590
msgid "Update WEI Registration"
msgstr "Modifier l'inscription WEI"
#: apps/wei/views.py:679
#: apps/wei/views.py:677
msgid "Delete WEI registration"
msgstr "Supprimer l'inscription WEI"
#: apps/wei/views.py:690
#: apps/wei/views.py:688
msgid "You don't have the right to delete this WEI registration."
msgstr "Vous n'avez pas la permission de supprimer cette inscription au WEI."
#: apps/wei/views.py:709
#: apps/wei/views.py:707
msgid "Validate WEI registration"
msgstr "Valider l'inscription WEI"
#: apps/wei/views.py:790
#: apps/wei/views.py:788
msgid "This user didn't give her/his caution check."
msgstr "Cet utilisateur n'a pas donné son chèque de caution."
#: apps/wei/views.py:827 apps/wei/views.py:880 apps/wei/views.py:890
#: apps/wei/views.py:825 apps/wei/views.py:878 apps/wei/views.py:888
#: templates/wei/survey.html:12 templates/wei/survey_closed.html:12
#: templates/wei/survey_end.html:12
msgid "Survey WEI"
@ -1882,6 +1930,10 @@ msgstr ""
msgid "Add alias"
msgstr "Ajouter un alias"
#: templates/member/autocomplete_model.html:11
msgid "Reset"
msgstr ""
#: templates/member/club_info.html:17
msgid "Club Parent"
msgstr "Club parent"
@ -2050,10 +2102,6 @@ msgstr "Sélection des destinataires"
msgid "Action"
msgstr "Action"
#: templates/note/transaction_form.html:104
msgid "Reason"
msgstr "Raison"
#: templates/note/transaction_form.html:113
msgid "Transfer type"
msgstr "Type de transfert"

View File

@ -23,10 +23,11 @@ class AmountInput(NumberInput):
class Autocomplete(TextInput):
template_name = "member/autocomplete_model.html"
def __init__(self, model, attrs=None):
def __init__(self, model, resetable=False, attrs=None):
super().__init__(attrs)
self.model = model
self.resetable = resetable
self.model_pk = None
class Media:
@ -34,6 +35,11 @@ class Autocomplete(TextInput):
js = ('js/autocomplete_model.js', )
def get_context(self, name, value, attrs):
context = super().get_context(name, value, attrs)
context['widget']['resetable'] = self.resetable
return context
def format_value(self, value):
if value:
self.attrs["model_pk"] = int(value)

View File

@ -10,6 +10,7 @@ $(document).ready(function () {
if (!name_field)
name_field = "name";
let input = target.val();
$("#" + prefix + "_reset").removeClass("d-none");
$.getJSON(api_url + (api_url.includes("?") ? "&" : "?") + "format=json&search=^" + input + api_url_suffix, function(objects) {
let html = "";
@ -39,4 +40,12 @@ $(document).ready(function () {
}
});
});
$(".autocomplete-reset").click(function() {
let name = $(this).attr("id").replace("_reset", "");
$("#" + name + "_pk").val("");
$("#" + name).val("");
$("#" + name + "_list").html("");
$(this).addClass("d-none");
});
});

View File

@ -1,3 +1,5 @@
{% load i18n %}
<input type="hidden" name="{{ widget.name }}" {% if widget.attrs.model_pk %}value="{{ widget.attrs.model_pk }}"{% endif %} id="{{ widget.attrs.id }}_pk">
<input type="text"
{% if widget.value != None and widget.value != "" %}value="{{ widget.value }}"{% endif %}
@ -5,5 +7,8 @@
{% for name, value in widget.attrs.items %}
{% ifnotequal value False %}{{ name }}{% ifnotequal value True %}="{{ value|stringformat:'s' }}"{% endifnotequal %}{% endifnotequal %}
{% endfor %}>
{% if widget.resetable %}
<a id="{{ widget.attrs.id }}_reset" class="btn btn-light autocomplete-reset{% if not widget.value %} d-none{% endif %}">{% trans "Reset" %}</a>
{% endif %}
<ul class="list-group list-group-flush" id="{{ widget.attrs.id }}_list">
</ul>

View File

@ -1,5 +1,7 @@
{% load render_table from django_tables2 %}
{% load i18n %}
{% load perms %}
{% if managers.data %}
<div class="card">
<div class="card-header position-relative" id="clubListHeading">
@ -29,7 +31,7 @@
{% if history_list.data %}
<div class="card">
<div class="card-header position-relative" id="historyListHeading">
<a class="font-weight-bold">
<a class="stretched-link font-weight-bold" {% if "note.view_note"|has_perm:club.note %} href="{% url 'note:transactions' pk=club.note.pk %}" {% endif %}>
<i class="fa fa-euro"></i> {% trans "Transaction history" %}
</a>
</div>

View File

@ -2,22 +2,22 @@
<div class="card bg-light shadow">
<div class="card-header text-center" >
<h4> {% trans "Account #" %} {{ object.pk }}</h4>
<h4> {% trans "Account #" %} {{ user.pk }}</h4>
</div>
<div class="card-top text-center">
<a href="{% url 'member:user_update_pic' object.pk %}">
<img src="{{ object.note.display_image.url }}" class="img-thumbnail mt-2" >
<a href="{% url 'member:user_update_pic' user.pk %}">
<img src="{{ user.note.display_image.url }}" class="img-thumbnail mt-2" >
</a>
</div>
<div class="card-body" id="profile_infos">
<dl class="row">
<dt class="col-xl-6">{% trans 'name'|capfirst %}, {% trans 'first name' %}</dt>
<dd class="col-xl-6">{{ object.last_name }} {{ object.first_name }}</dd>
<dd class="col-xl-6">{{ user.last_name }} {{ user.first_name }}</dd>
<dt class="col-xl-6">{% trans 'username'|capfirst %}</dt>
<dd class="col-xl-6">{{ object.username }}</dd>
<dd class="col-xl-6">{{ user.username }}</dd>
{% if object.pk == user.pk %}
{% if user.pk == user.pk %}
<dt class="col-xl-6">{% trans 'password'|capfirst %}</dt>
<dd class="col-xl-6">
<a class="small" href="{% url 'password_change' %}">
@ -27,25 +27,25 @@
{% endif %}
<dt class="col-xl-6">{% trans 'section'|capfirst %}</dt>
<dd class="col-xl-6">{{ object.profile.section }}</dd>
<dd class="col-xl-6">{{ user.profile.section }}</dd>
<dt class="col-xl-6">{% trans 'address'|capfirst %}</dt>
<dd class="col-xl-6">{{ object.profile.address }}</dd>
<dd class="col-xl-6">{{ user.profile.address }}</dd>
<dt class="col-xl-6">{% trans 'balance'|capfirst %}</dt>
<dd class="col-xl-6">{{ object.note.balance | pretty_money }}</dd>
<dd class="col-xl-6">{{ user.note.balance | pretty_money }}</dd>
<dt class="col-xl-6"> <a href="{% url 'member:user_alias' object.pk %}">{% trans 'aliases'|capfirst %}</a></dt>
<dd class="col-xl-6 text-truncate">{{ object.note.alias_set.all|join:", " }}</dd>
<dt class="col-xl-6"> <a href="{% url 'member:user_alias' user.pk %}">{% trans 'aliases'|capfirst %}</a></dt>
<dd class="col-xl-6 text-truncate">{{ user.note.alias_set.all|join:", " }}</dd>
</dl>
{% if object.pk == user.pk %}
{% if user.pk == user.pk %}
<a class="small" href="{% url 'member:auth_token' %}">{% trans 'Manage auth token' %}</a>
{% endif %}
</div>
<div class="card-footer text-center">
<a class="btn btn-primary btn-sm" href="{% url 'member:user_update_profile' object.pk %}">{% trans 'Update Profile' %}</a>
{% url 'member:user_detail' object.pk as user_profile_url %}
<a class="btn btn-primary btn-sm" href="{% url 'member:user_update_profile' user.pk %}">{% trans 'Update Profile' %}</a>
{% url 'member:user_detail' user.pk as user_profile_url %}
{%if request.path_info != user_profile_url %}
<a class="btn btn-primary btn-sm" href="{{ user_profile_url }}">{% trans 'View Profile' %}</a>
{% endif %}

View File

@ -2,10 +2,10 @@
{% load i18n %}
{% load perms %}
{% if not object.profile.email_confirmed and "member.change_profile_email_confirmed"|has_perm:object.profile %}
{% if not object.profile.email_confirmed and "member.change_profile_email_confirmed"|has_perm:user.profile %}
<div class="alert alert-warning">
{% trans "This user doesn't have confirmed his/her e-mail address." %}
<a href="{% url "registration:email_validation_resend" pk=object.pk %}">{% trans "Click here to resend a validation link." %}</a>
<a href="{% url "registration:email_validation_resend" pk=user.pk %}">{% trans "Click here to resend a validation link." %}</a>
</div>
{% endif %}
@ -22,9 +22,7 @@
<div class="card">
<div class="card-header position-relative" id="historyListHeading">
<a class="collapsed font-weight-bold"
data-toggle="collapse" data-target="#historyListCollapse"
aria-expanded="true" aria-controls="historyListCollapse">
<a class="stretched-link font-weight-bold" {% if "note.view_note"|has_perm:user.note %} href="{% url 'note:transactions' pk=user.note.pk %}" {% endif %}>
<i class="fa fa-euro"></i> {% trans "Transaction history" %}
</a>
</div>

View File

@ -0,0 +1,57 @@
{% extends "member/noteowner_detail.html" %}
{% load render_table from django_tables2 %}
{% load crispy_forms_tags %}
{% block profile_info %}
{% if note.club.weiclub %}
{% with club=note.club.weiclub %}
{% include "wei/weiclub_info.html" %}
{% endwith %}
{% elif note.club %}
{% with club=note.club %}
{% include "member/club_info.html" %}
{% endwith %}
{% elif note.user %}
{% with user=note.user %}
{% include "member/profile_info.html" %}
{% endwith %}
{% endif %}
{% endblock %}
{% block profile_content %}
{% crispy form %}
<div id="table">
{% render_table table %}
</div>
{% endblock %}
{% block extrajavascript %}
<script>
function refreshHistory() {
$("#history_list").load("{% url 'note:transactions' pk=object.pk %} #history_list");
$("#profile_infos").load("{% url 'note:transactions' pk=object.pk %} #profile_infos");
}
function refreshFilters() {
let filters = "";
filters += "source=" + $("#id_source_pk").val();
filters += "&destination=" + $("#id_destination_pk").val();
filters += $("input[name='type']:checked").map(function() {
return "&type=" + $(this).val();
}).toArray().join("");
filters += "&reason=" + $("#id_reason").val();
filters += "&valid=" + ($("#id_valid").is(":checked") ? "1" : "");
filters += "&amount_gte=" + $("#id_amount_gte").val();
filters += "&amount_lte=" + $("#id_amount_lte").val();
filters += "&created_after=" + $("#id_created_after").val();
filters += "&created_before=" + $("#id_created_before").val();
console.log(filters.replace(" ", "%20"));
$("#table").load(location.pathname + "?" + filters.replaceAll(" ", "%20") + " #table");
}
$(document).ready(function() {
$("input").change(refreshFilters);
$("input").keyup(refreshFilters);
});
</script>
{% endblock %}

View File

@ -1,59 +1,12 @@
{% load render_table from django_tables2 %}
{% load i18n %}
{% load perms %}
<div class="card">
<div class="card-header text-center">
<h4>WEI</h4>
</div>
<div class="card-body">
<p>LE WEI, c'est cool !</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Dapibus ultrices in iaculis nunc sed augue. In hendrerit gravida rutrum quisque non tellus orci
ac. Massa vitae tortor condimentum lacinia quis vel eros. Elit ut aliquam purus sit amet. Aliquam faucibus
purus in massa tempor. Quisque id diam vel quam elementum pulvinar etiam non. Condimentum id venenatis a
condimentum vitae sapien pellentesque habitant. Egestas congue quisque egestas diam in. Vestibulum rhoncus
est pellentesque elit ullamcorper. Massa sed elementum tempus egestas sed sed. Sapien pellentesque habitant
morbi tristique. Lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare. Sed
adipiscing diam donec adipiscing. Leo integer malesuada nunc vel risus commodo viverra maecenas.
</p>
<p>
Fusce id velit ut tortor pretium viverra suspendisse. Urna condimentum mattis pellentesque id nibh tortor id
aliquet. Vel facilisis volutpat est velit egestas dui. Turpis egestas sed tempus urna et pharetra pharetra
massa massa. Eget nunc scelerisque viverra mauris in. Etiam dignissim diam quis enim. Urna cursus eget nunc
scelerisque viverra mauris in aliquam sem. Amet porttitor eget dolor morbi non arcu risus quis. Ullamcorper
sit amet risus nullam eget felis. Ullamcorper eget nulla facilisi etiam dignissim diam quis. Enim nulla
aliquet porttitor lacus luctus accumsan tortor. Urna condimentum mattis pellentesque id nibh tortor id.
Feugiat in fermentum posuere urna nec. Risus nec feugiat in fermentum posuere urna nec tincidunt. Porttitor
massa id neque aliquam vestibulum morbi. Diam quis enim lobortis scelerisque. Ornare massa eget egestas
purus. Ut tortor pretium viverra suspendisse. Purus in mollis nunc sed. Tristique magna sit amet purus
gravida.
</p>
<p>
Ut porttitor leo a diam sollicitudin tempor. Viverra nam libero justo laoreet sit amet cursus sit amet.
Lectus arcu bibendum at varius vel pharetra vel turpis nunc. Vivamus arcu felis bibendum ut tristique et
egestas quis ipsum. Parturient montes nascetur ridiculus mus mauris. A cras semper auctor neque vitae
tempus quam pellentesque. Netus et malesuada fames ac. Mauris in aliquam sem fringilla ut. Sapien
pellentesque habitant morbi tristique. Mauris sit amet massa vitae tortor condimentum. Sagittis
aliquam malesuada bibendum arcu vitae elementum curabitur vitae nunc. Amet consectetur adipiscing elit
duis tristique sollicitudin nibh sit. Nunc mattis enim ut tellus elementum. Sapien eget mi proin sed libero
enim. Pulvinar sapien et ligula ullamcorper. Nibh mauris cursus mattis molestie a iaculis at erat
pellentesque. Molestie at elementum eu facilisis. Velit sed ullamcorper morbi tincidunt. Quam vulputate
dignissim suspendisse in est ante.
</p>
<p>
Id cursus metus aliquam eleifend mi. Eu turpis egestas pretium aenean pharetra magna ac. Faucibus ornare
suspendisse sed nisi lacus sed viverra tellus. Sed vulputate mi sit amet mauris commodo. Lacus laoreet non
curabitur gravida arcu ac. At ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget. Fusce ut
placerat orci nulla pellentesque dignissim. Quis blandit turpis cursus in hac habitasse platea dictumst
quisque. Tellus id interdum velit laoreet id donec ultrices. Risus feugiat in ante metus dictum. Velit ut
tortor pretium viverra suspendisse. Lacus vel facilisis volutpat est velit egestas dui id. Nunc eget lorem
dolor sed viverra ipsum nunc aliquet bibendum. Varius quam quisque id diam vel quam. Orci dapibus ultrices
in iaculis. Neque gravida in fermentum et sollicitudin ac orci.
</p>
</div>
{% if club.is_current_wei %}
@ -101,7 +54,7 @@
{% if history_list.data %}
<div class="card">
<div class="card-header position-relative" id="historyListHeading">
<a class="font-weight-bold">
<a class="stretched-link font-weight-bold" {% if "note.view_note"|has_perm:club.note %} href="{% url 'note:transactions' pk=club.note.pk %}" {% endif %}>
<i class="fa fa-euro"></i> {% trans "Transaction history" %}
</a>
</div>