diff --git a/kfet/autocomplete.py b/kfet/autocomplete.py index 2a24a51e..896eff6e 100644 --- a/kfet/autocomplete.py +++ b/kfet/autocomplete.py @@ -1,9 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import (absolute_import, division, - print_function, unicode_literals) -from builtins import * - from django.shortcuts import render from django.http import Http404 from django.db.models import Q @@ -11,6 +7,7 @@ from gestioncof.models import User, Clipper from kfet.decorators import teamkfet_required from kfet.models import Account + @teamkfet_required def account_create(request): if "q" not in request.GET: @@ -25,48 +22,48 @@ def account_create(request): queries = {} search_words = q.split() - queries['kfet'] = Account.objects - queries['users_cof'] = User.objects.filter(Q(profile__is_cof = True)) - queries['users_notcof'] = User.objects.filter(Q(profile__is_cof = False)) - queries['clippers'] = Clipper.objects + queries['kfet'] = Account.objects + queries['users_cof'] = User.objects.filter(Q(profile__is_cof=True)) + queries['users_notcof'] = User.objects.filter(Q(profile__is_cof=False)) + queries['clippers'] = Clipper.objects for word in search_words: queries['kfet'] = queries['kfet'].filter( - Q(cofprofile__user__username__icontains = word) - | Q(cofprofile__user__first_name__icontains = word) - | Q(cofprofile__user__last_name__icontains = word) + Q(cofprofile__user__username__icontains=word) | + Q(cofprofile__user__first_name__icontains=word) | + Q(cofprofile__user__last_name__icontains=word) ) queries['users_cof'] = queries['users_cof'].filter( - Q(username__icontains = word) - | Q(first_name__icontains = word) - | Q(last_name__icontains = word) + Q(username__icontains=word) | + Q(first_name__icontains=word) | + Q(last_name__icontains=word) ) queries['users_notcof'] = queries['users_notcof'].filter( - Q(username__icontains = word) - | Q(first_name__icontains = word) - | Q(last_name__icontains = word) + Q(username__icontains=word) | + Q(first_name__icontains=word) | + Q(last_name__icontains=word) ) - queries['clippers'] = queries['clippers'].filter( - Q(username__icontains = word) - | Q(fullname__icontains = word) + queries['clippers'] = queries['clippers'].filter( + Q(username__icontains=word) | + Q(fullname__icontains=word) ) queries['kfet'] = queries['kfet'].distinct() - usernames = list( \ + usernames = list( queries['kfet'].values_list('cofprofile__user__username', flat=True)) - queries['kfet'] = [ (account, account.cofprofile.user) \ - for account in queries['kfet'] ] + queries['kfet'] = [(account, account.cofprofile.user) + for account in queries['kfet']] - queries['users_cof'] = \ + queries['users_cof'] = \ queries['users_cof'].exclude(username__in=usernames).distinct() - queries['users_notcof'] = \ + queries['users_notcof'] = \ queries['users_notcof'].exclude(username__in=usernames).distinct() - usernames += list( \ + usernames += list( queries['users_cof'].values_list('username', flat=True)) - usernames += list( \ + usernames += list( queries['users_notcof'].values_list('username', flat=True)) queries['clippers'] = \ @@ -80,3 +77,25 @@ def account_create(request): data['options'] = options return render(request, "kfet/account_create_autocomplete.html", data) + + +def account_search(request): + if "q" not in request.GET: + raise Http404 + q = request.GET.get("q") + words = q.split() + + data = {'q': q} + + for word in words: + query = Account.objects.filter( + Q(cofprofile__user__username__icontains=word) | + Q(cofprofile__user__first_name__icontains=word) | + Q(cofprofile__user__last_name__icontains=word) + ).distinct() + + query = [(account.trigramme, account.cofprofile.user.get_full_name()) + for account in query] + + data['accounts'] = query + return render(request, 'kfet/account_search_autocomplete.html', data) diff --git a/kfet/forms.py b/kfet/forms.py index 0c563b04..fe2e4a9c 100644 --- a/kfet/forms.py +++ b/kfet/forms.py @@ -1,21 +1,17 @@ # -*- coding: utf-8 -*- -from __future__ import (absolute_import, division, - print_function, unicode_literals) -from builtins import * - from decimal import Decimal from django import forms from django.core.exceptions import ValidationError from django.core.validators import MinLengthValidator from django.contrib.auth.models import User, Group, Permission from django.contrib.contenttypes.models import ContentType -from django.forms import modelformset_factory, inlineformset_factory -from django.forms.models import BaseInlineFormSet +from django.forms import modelformset_factory from django.utils import timezone -from kfet.models import (Account, Checkout, Article, OperationGroup, Operation, +from kfet.models import ( + Account, Checkout, Article, OperationGroup, Operation, CheckoutStatement, ArticleCategory, Settings, AccountNegative, Transfer, - TransferGroup, Supplier, Inventory, InventoryArticle) + TransferGroup, Supplier) from gestioncof.models import CofProfile # ----- @@ -131,7 +127,16 @@ class UserRestrictTeamForm(UserForm): class UserGroupForm(forms.ModelForm): groups = forms.ModelMultipleChoiceField( - Group.objects.filter(name__icontains='K-Fêt')) + Group.objects.filter(name__icontains='K-Fêt'), + required=False) + + def clean_groups(self): + groups = self.cleaned_data.get('groups') + # Si aucun groupe, on le dénomme + if not groups: + groups = self.instance.groups.exclude(name__icontains='K-Fêt') + return groups + class Meta: model = User fields = ['groups'] diff --git a/kfet/static/kfet/css/jconfirm-kfet.css b/kfet/static/kfet/css/jconfirm-kfet.css index 4269fbcc..0bd53ab7 100644 --- a/kfet/static/kfet/css/jconfirm-kfet.css +++ b/kfet/static/kfet/css/jconfirm-kfet.css @@ -83,3 +83,24 @@ padding-right: 50px; padding-left: 50px; } + +/* Account autocomplete window */ + +#account_results ul { + list-style-type:none; + background:rgba(255,255,255,0.9); + padding:0; +} + +#account_results li { + display:block; + padding:5px 20px; + height:100%; + width:100%; +} + +#account_results .hilight { + background:rgba(200,16,46,0.9); + color:#fff; + text-decoration:none; +} diff --git a/kfet/templates/kfet/account_create_autocomplete.html b/kfet/templates/kfet/account_create_autocomplete.html index 1185c3a8..1a869c86 100644 --- a/kfet/templates/kfet/account_create_autocomplete.html +++ b/kfet/templates/kfet/account_create_autocomplete.html @@ -7,7 +7,7 @@ {% if kfet %} -
  • Comptes existant
  • +
  • Comptes existants
  • {% for account, user in kfet %}
  • {{ account }} [{{ user|highlight_user:q }}]
  • {% endfor %} diff --git a/kfet/templates/kfet/account_search_autocomplete.html b/kfet/templates/kfet/account_search_autocomplete.html new file mode 100644 index 00000000..e18eb1eb --- /dev/null +++ b/kfet/templates/kfet/account_search_autocomplete.html @@ -0,0 +1,14 @@ +{% load kfet_tags %} + + + diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index f47da827..3fba824d 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -4,6 +4,7 @@ {% block extra_head %} + @@ -261,12 +262,56 @@ $(document).ready(function() { buttons += ''; } else { var url_base = '{% url 'kfet.account' %}' - buttons += ''; + buttons += ''; } } account_container.find('.buttons').html(buttons); } + // Search for an account + function searchAccount() { + var content = '
    ' ; + $.dialog({ + title: 'Recherche de compte', + content: content, + backgroundDismiss: true, + animation: 'top', + closeAnimation: 'bottom', + keyboardEnabled: true, + onOpen: function() { + var that=this ; + $('input#search_autocomplete').yourlabsAutocomplete({ + url: '{% url "kfet.account.search.autocomplete" %}', + minimumCharacters: 2, + id: 'search_autocomplete', + choiceSelector: '.choice', + placeholder: "Chercher un utilisateur K-Fêt", + box: $("#account_results"), + }); + $('input#search_autocomplete').bind( + 'selectChoice', + function(e, choice, autocomplete) { + autocomplete.hide() ; + triInput.val(choice.find('.trigramme').text()) ; + triInput.trigger('input') ; + that.close() ; + }); + } + }); + } + + account_container.on('click', '.search', function () { + searchAccount() ; + }) ; + + account_container.on('keydown', function(e) { + if (e.which == 70 && e.ctrlKey) { + // Ctrl + F : universal search shortcut + searchAccount() ; + e.preventDefault() ; + } + }); + // Clear data function resetAccountData() { account_data = account_data_default; @@ -992,7 +1037,7 @@ $(document).ready(function() { var title = is_checkout ? 'Montant de la charge' : "Montant de l'édition"; $.confirm({ title: title, - content: '', + content: '', backgroundDismiss: true, animation:'top', closeAnimation:'bottom', @@ -1019,7 +1064,7 @@ $(document).ready(function() { function askWithdraw() { $.confirm({ title: 'Montant du retrait', - content: '', + content: '', backgroundDismiss: true, animation:'top', closeAnimation:'bottom', @@ -1203,7 +1248,7 @@ $(document).ready(function() { function askAddcost(errors = '') { $.confirm({ title: 'Majoration', - content: errors + '', + content: errors + '', backgroundDismiss: true, animation:'top', closeAnimation:'bottom', @@ -1290,7 +1335,7 @@ $(document).ready(function() { } for (var i=0; i%s)" % q2, re.IGNORECASE) - return mark_safe(re.sub(pattern, r"\g", text)) + return mark_safe( + re.sub(pattern, + r"\g", + escape(text))) + @register.filter(is_safe=True) def highlight_user(user, q): @@ -25,7 +26,8 @@ def highlight_user(user, q): text = "%s %s (%s)" % (user.first_name, user.last_name, user.username) else: text = user.username - return highlight_text(escape(text), q) + return highlight_text(text, q) + @register.filter(is_safe=True) def highlight_clipper(clipper, q): @@ -33,9 +35,11 @@ def highlight_clipper(clipper, q): text = "%s (%s)" % (clipper.fullname, clipper.username) else: text = clipper.username - return highlight_text(escape(text), q) + return highlight_text(text, q) + @register.filter() def ukf(balance, is_cof): grant = is_cof and (1 + Settings.SUBVENTION_COF() / 100) or 1 - return floor(balance * 10 * grant) + # float nécessaire car sinon problème avec le round de future.builtins + return floor(float(balance) * 10 * grant) diff --git a/kfet/urls.py b/kfet/urls.py index 9b9ebf21..271ed917 100644 --- a/kfet/urls.py +++ b/kfet/urls.py @@ -1,9 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import (absolute_import, division, - print_function, unicode_literals) -from builtins import * - from django.conf.urls import url from django.contrib.auth.decorators import permission_required from kfet import views @@ -12,11 +8,11 @@ from kfet.decorators import teamkfet_required urlpatterns = [ url(r'^$', views.home, - name = 'kfet.home'), + name='kfet.home'), url(r'^login/genericteam$', views.login_genericteam, - name = 'kfet.login.genericteam'), + name='kfet.login.genericteam'), url(r'^history$', views.history, - name = 'kfet.history'), + name='kfet.history'), # ----- # Account urls @@ -24,45 +20,53 @@ urlpatterns = [ # Account - General url(r'^accounts/$', views.account, - name = 'kfet.account'), + name='kfet.account'), url(r'^accounts/is_validandfree$', views.account_is_validandfree_ajax, - name = 'kfet.account.is_validandfree.ajax'), + name='kfet.account.is_validandfree.ajax'), # Account - Create url(r'^accounts/new$', views.account_create, - name = 'kfet.account.create'), + name='kfet.account.create'), url(r'^accounts/new_special$', views.account_create_special, - name = 'kfet.account.create_special'), + name='kfet.account.create_special'), url(r'^accounts/new/user/(?P.+)$', views.account_create_ajax, - name = 'kfet.account.create.fromuser'), - url(r'^accounts/new/clipper/(?P.+)$', views.account_create_ajax, - name = 'kfet.account.create.fromclipper'), + name='kfet.account.create.fromuser'), + url(r'^accounts/new/clipper/(?P.+)$', + views.account_create_ajax, + name='kfet.account.create.fromclipper'), url(r'^accounts/new/empty$', views.account_create_ajax, - name = 'kfet.account.create.empty'), + name='kfet.account.create.empty'), url(r'^autocomplete/account_new$', autocomplete.account_create, - name = 'kfet.account.create.autocomplete'), + name='kfet.account.create.autocomplete'), + + # Account - Search + url(r'^autocomplete/account_search$', autocomplete.account_search, + name='kfet.account.search.autocomplete'), # Account - Read url(r'^accounts/(?P.{3})$', views.account_read, - name = 'kfet.account.read'), + name='kfet.account.read'), # Account - Update url(r'^accounts/(?P.{3})/edit$', views.account_update, - name = 'kfet.account.update'), + name='kfet.account.update'), # Account - Groups url(r'^accounts/groups$', views.account_group, - name = 'kfet.account.group'), + name='kfet.account.group'), url(r'^accounts/groups/new$', - permission_required('kfet.manage_perms')(views.AccountGroupCreate.as_view()), - name = 'kfet.account.group.create'), + permission_required('kfet.manage_perms') + (views.AccountGroupCreate.as_view()), + name='kfet.account.group.create'), url(r'^accounts/groups/(?P\d+)/edit$', - permission_required('kfet.manage_perms')(views.AccountGroupUpdate.as_view()), - name = 'kfet.account.group.update'), + permission_required('kfet.manage_perms') + (views.AccountGroupUpdate.as_view()), + name='kfet.account.group.update'), url(r'^accounts/negatives$', - permission_required('kfet.view_negs')(views.AccountNegativeList.as_view()), - name = 'kfet.account.negative'), + permission_required('kfet.view_negs') + (views.AccountNegativeList.as_view()), + name='kfet.account.negative'), # ----- # Checkout urls @@ -71,34 +75,36 @@ urlpatterns = [ # Checkout - General url('^checkouts/$', teamkfet_required(views.CheckoutList.as_view()), - name = 'kfet.checkout'), + name='kfet.checkout'), # Checkout - Create url('^checkouts/new$', teamkfet_required(views.CheckoutCreate.as_view()), - name = 'kfet.checkout.create'), + name='kfet.checkout.create'), # Checkout - Read url('^checkouts/(?P\d+)$', teamkfet_required(views.CheckoutRead.as_view()), - name = 'kfet.checkout.read'), + name='kfet.checkout.read'), # Checkout - Update url('^checkouts/(?P\d+)/edit$', teamkfet_required(views.CheckoutUpdate.as_view()), - name = 'kfet.checkout.update'), + name='kfet.checkout.update'), - ### Checkout Statements urls + # ----- + # Checkout Statement urls + # ----- # Checkout Statement - General url('^checkouts/statements/$', teamkfet_required(views.CheckoutStatementList.as_view()), - name = 'kfet.checkoutstatement'), + name='kfet.checkoutstatement'), # Checkout Statement - Create url('^checkouts/(?P\d+)/statements/add', teamkfet_required(views.CheckoutStatementCreate.as_view()), - name = 'kfet.checkoutstatement.create'), + name='kfet.checkoutstatement.create'), # Checkout Statement - Update url('^checkouts/(?P\d+)/statements/(?P\d+)/edit', teamkfet_required(views.CheckoutStatementUpdate.as_view()), - name = 'kfet.checkoutstatement.update'), + name='kfet.checkoutstatement.update'), # ----- # Article urls @@ -107,46 +113,46 @@ urlpatterns = [ # Article - General url('^articles/$', teamkfet_required(views.ArticleList.as_view()), - name = 'kfet.article'), + name='kfet.article'), # Article - Create url('^articles/new$', teamkfet_required(views.ArticleCreate.as_view()), - name = 'kfet.article.create'), + name='kfet.article.create'), # Article - Read url('^articles/(?P\d+)$', teamkfet_required(views.ArticleRead.as_view()), - name = 'kfet.article.read'), + name='kfet.article.read'), # Article - Update url('^articles/(?P\d+)/edit$', teamkfet_required(views.ArticleUpdate.as_view()), - name = 'kfet.article.update'), + name='kfet.article.update'), # ----- # K-Psul urls # ----- - url('^k-psul/$', views.kpsul, name = 'kfet.kpsul'), + url('^k-psul/$', views.kpsul, name='kfet.kpsul'), url('^k-psul/checkout_data$', views.kpsul_checkout_data, - name = 'kfet.kpsul.checkout_data'), + name='kfet.kpsul.checkout_data'), url('^k-psul/perform_operations$', views.kpsul_perform_operations, - name = 'kfet.kpsul.perform_operations'), + name='kfet.kpsul.perform_operations'), url('^k-psul/cancel_operations$', views.kpsul_cancel_operations, - name = 'kfet.kpsul.cancel_operations'), + name='kfet.kpsul.cancel_operations'), url('^k-psul/articles_data', views.kpsul_articles_data, - name = 'kfet.kpsul.articles_data'), + name='kfet.kpsul.articles_data'), url('^k-psul/update_addcost$', views.kpsul_update_addcost, - name = 'kfet.kpsul.update_addcost'), + name='kfet.kpsul.update_addcost'), url('^k-psul/get_settings$', views.kpsul_get_settings, - name = 'kfet.kpsul.get_settings'), + name='kfet.kpsul.get_settings'), # ----- # JSON urls # ----- url(r'^history.json$', views.history_json, - name = 'kfet.history.json'), + name='kfet.history.json'), url(r'^accounts/read.json$', views.account_read_json, - name = 'kfet.account.read.json'), + name='kfet.account.read.json'), # ----- @@ -154,24 +160,26 @@ urlpatterns = [ # ----- url(r'^settings/$', - permission_required('kfet.change_settings')(views.SettingsList.as_view()), - name = 'kfet.settings'), + permission_required('kfet.change_settings') + (views.SettingsList.as_view()), + name='kfet.settings'), url(r'^settings/(?P\d+)/edit$', - permission_required('kfet.change_settings')(views.SettingsUpdate.as_view()), - name = 'kfet.settings.update'), + permission_required('kfet.change_settings') + (views.SettingsUpdate.as_view()), + name='kfet.settings.update'), # ----- # Transfers urls # ----- url(r'^transfers/$', views.transfers, - name = 'kfet.transfers'), + name='kfet.transfers'), url(r'^transfers/new$', views.transfers_create, - name = 'kfet.transfers.create'), + name='kfet.transfers.create'), url(r'^transfers/perform$', views.perform_transfers, - name = 'kfet.transfers.perform'), + name='kfet.transfers.perform'), url(r'^transfers/cancel$', views.cancel_transfers, - name = 'kfet.transfers.cancel'), + name='kfet.transfers.cancel'), # ----- # Inventories urls @@ -179,12 +187,12 @@ urlpatterns = [ url(r'^inventaires/$', teamkfet_required(views.InventoryList.as_view()), - name = 'kfet.inventory'), + name='kfet.inventory'), url(r'^inventaires/new$', views.inventory_create, - name = 'kfet.inventory.create'), + name='kfet.inventory.create'), url(r'^inventaires/(?P\d+)$', teamkfet_required(views.InventoryRead.as_view()), - name = 'kfet.inventory.read'), + name='kfet.inventory.read'), # ----- # Order urls @@ -192,15 +200,15 @@ urlpatterns = [ url(r'^orders/$', teamkfet_required(views.OrderList.as_view()), - name = 'kfet.order'), + name='kfet.order'), url(r'^orders/(?P\d+)$', teamkfet_required(views.OrderRead.as_view()), - name = 'kfet.order.read'), + name='kfet.order.read'), url(r'^orders/suppliers/(?P\d+)/edit$', teamkfet_required(views.SupplierUpdate.as_view()), - name = 'kfet.order.supplier.update'), + name='kfet.order.supplier.update'), url(r'^orders/suppliers/(?P\d+)/new-order$', views.order_create, - name = 'kfet.order.new'), + name='kfet.order.new'), url(r'^orders/(?P\d+)/to_inventory$', views.order_to_inventory, - name = 'kfet.order.to_inventory'), + name='kfet.order.to_inventory'), ]