From 971848cb1b44aa0911a062bff374ed6f8028bbce Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Thu, 1 Dec 2016 01:29:28 -0200 Subject: [PATCH 01/16] database lookups --- kfet/views.py | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/kfet/views.py b/kfet/views.py index f95fb2c6..e8080774 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -18,7 +18,7 @@ from django.contrib.auth.models import User, Permission, Group from django.http import HttpResponse, JsonResponse, Http404 from django.forms import modelformset_factory, formset_factory from django.db import IntegrityError, transaction -from django.db.models import F, Sum, Prefetch, Count, Func +from django.db.models import Q, F, Sum, Prefetch, Count, Func from django.db.models.functions import Coalesce from django.utils import timezone from django.utils.crypto import get_random_string @@ -26,7 +26,7 @@ from gestioncof.models import CofProfile, Clipper from kfet.decorators import teamkfet_required from kfet.models import (Account, Checkout, Article, Settings, AccountNegative, CheckoutStatement, GenericTeamToken, Supplier, SupplierArticle, Inventory, - InventoryArticle, Order, OrderArticle) + InventoryArticle, Order, OrderArticle, TransferGroup, Transfer) from kfet.forms import * from collections import defaultdict from kfet import consumers @@ -1268,35 +1268,63 @@ def history_json(request): # Récupération des paramètres from_date = request.POST.get('from', None) to_date = request.POST.get('to', None) - limit = request.POST.get('limit', None); checkouts = request.POST.getlist('checkouts[]', None) accounts = request.POST.getlist('accounts[]', None) # Construction de la requête (sur les opérations) pour le prefetch - queryset_prefetch = Operation.objects.select_related( + ope_queryset_prefetch = Operation.objects.select_related( 'canceled_by__trigramme', 'addcost_for__trigramme', 'article__name') + ope_prefetch = Prefetch('opes', + queryset = ope_queryset_prefetch) + + transfer_queryset_prefetch = Transfer.objects.select_related( + 'from_acc__trigramme', 'to_acc__trigramme', + 'canceled_by__trigramme') + + if accounts: + transfer_queryset_prefetch = transfer_queryset_prefetch.filter( + Q(from_acc__trigramme__in=accounts) | + Q(to_acc__trigramme__in=accounts)) + + if not request.user.has_perm('kfet.is_team'): + acc = request.user.profile.account_kfet + transfer_queryset_prefetch = transfer_queryset_prefetch.filter( + Q(from_acc=acc) | Q(to_acc=acc)) + + transfer_prefetch = Prefetch('transfers', + queryset=transfer_queryset_prefetch, + to_attr='filtered_transfers') + # Construction de la requête principale opegroups = (OperationGroup.objects - .prefetch_related(Prefetch('opes', queryset = queryset_prefetch)) + .prefetch_related(ope_prefetch) .select_related('on_acc__trigramme', 'valid_by__trigramme') .order_by('at') ) + + transfergroups = ( + TransferGroup.objects + .prefetch_related(transfer_prefetch) + .select_related('valid_by__trigramme') + .order_by('at')) + # Application des filtres if from_date: opegroups = opegroups.filter(at__gte=from_date) + transfergroups = transfergroups.filter(at__gte=from_date) if to_date: opegroups = opegroups.filter(at__lt=to_date) + transfergroups = transfergroups.filter(at__lt=to_date) if checkouts: opegroups = opegroups.filter(checkout_id__in=checkouts) + transfergroups = TransferGroup.objects.none() if accounts: opegroups = opegroups.filter(on_acc_id__in=accounts) # Un non-membre de l'équipe n'a que accès à son historique if not request.user.has_perm('kfet.is_team'): opegroups = opegroups.filter(on_acc=request.user.profile.account_kfet) - if limit: - opegroups = opegroups[:limit] # Construction de la réponse From 5a354c61a0905cc379a77fa8ebcfea2545f20c33 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Fri, 2 Dec 2016 00:16:40 -0200 Subject: [PATCH 02/16] fetch transfers as well --- kfet/views.py | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/kfet/views.py b/kfet/views.py index e8080774..b270a96d 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -1331,10 +1331,10 @@ def history_json(request): opegroups_list = [] for opegroup in opegroups: opegroup_dict = { + 'type' : 'opegroup', 'id' : opegroup.id, 'amount' : opegroup.amount, 'at' : opegroup.at, - 'checkout_id': opegroup.checkout_id, 'is_cof' : opegroup.is_cof, 'comment' : opegroup.comment, 'opes' : [], @@ -1363,7 +1363,41 @@ def history_json(request): ope.canceled_by and ope.canceled_by.trigramme or None) opegroup_dict['opes'].append(ope_dict) opegroups_list.append(opegroup_dict) - return JsonResponse({ 'opegroups': opegroups_list }) + + for transfergroup in transfergroups: + if transfergroup.filtered_transfers: + transfergroup_dict = { + 'type': 'transfergroup', + 'id': transfergroup.id, + 'at': transfergroup.at, + 'comment': transfergroup.comment, + 'opes': [], + } + if request.user.has_perm('kfet.is_team'): + transfergroup_dict['valid_by__trigramme'] = ( + transfergroup.valid_by + and transfergroup.valid_by.trigramme + or None) + + for transfer in transfergroup.filtered_transfers: + transfer_dict = { + 'id': transfer.id, + 'amount': transfer.amount, + 'canceled_at': transfer.canceled_at, + 'from_acc': transfer.from_acc.trigramme, + 'to_acc': transfer.to_acc.trigramme, + } + if request.user.has_perm('kfet.is_team'): + transfer_dict['canceled_by__trigramme'] = ( + transfer.canceled_by + and transfer.canceled_by.trigramme + or None) + transfergroup_dict['opes'].append(transfer_dict) + opegroups_list.append(transfergroup_dict) + + opegroups_list.sort(key=lambda group: group['at']) + + return JsonResponse({'opegroups': opegroups_list}) @teamkfet_required def kpsul_articles_data(request): From f747c0c389f54c5b04ec903f0dfc50c5ebebd305 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Fri, 2 Dec 2016 00:17:03 -0200 Subject: [PATCH 03/16] print transfers (BROKEN) --- kfet/static/kfet/js/history.js | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/kfet/static/kfet/js/history.js b/kfet/static/kfet/js/history.js index 291c106d..a50dbb6b 100644 --- a/kfet/static/kfet/js/history.js +++ b/kfet/static/kfet/js/history.js @@ -15,10 +15,18 @@ function KHistory(options={}) { var trigramme = opegroup['on_acc_trigramme']; var is_cof = opegroup['is_cof']; - for (var i=0; i', template_opegroup: '
', template_ope: '
', + template_transfer: '
', display_trigramme: true, } From ac0356386a0f233df8d2150168a7cd0e6204a89b Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Fri, 9 Dec 2016 00:26:07 -0200 Subject: [PATCH 04/16] add css for transfers --- kfet/static/kfet/css/history.css | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/kfet/static/kfet/css/history.css b/kfet/static/kfet/css/history.css index 976f5782..64b82f96 100644 --- a/kfet/static/kfet/css/history.css +++ b/kfet/static/kfet/css/history.css @@ -40,6 +40,11 @@ width:90px; } +#history .opegroup .info { + text-align:center; + width:145px; +} + #history .opegroup .valid_by { padding-left:20px } @@ -67,6 +72,10 @@ text-align:right; } +#history .ope .glyphicon { + padding-left:15px; +} + #history .ope .infos2 { padding-left:15px; } From 36edc334d44dc5fb08662d58f111538c42e8d8a1 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Fri, 9 Dec 2016 00:26:25 -0200 Subject: [PATCH 05/16] add transfer information --- kfet/static/kfet/js/history.js | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/kfet/static/kfet/js/history.js b/kfet/static/kfet/js/history.js index a50dbb6b..e9486a1e 100644 --- a/kfet/static/kfet/js/history.js +++ b/kfet/static/kfet/js/history.js @@ -22,6 +22,7 @@ function KHistory(options={}) { $opegroup.after($ope); } } else { + $opegroup.addClass("transfergroup"); for (var i=0; i', template_opegroup: '
', + template_transfergroup: '
', template_ope: '
', - template_transfer: '
', + template_transfer: '
', display_trigramme: true, } From 85af7fe485f2d4cb46ff269aeddffea3f24c8691 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Fri, 9 Dec 2016 17:29:40 -0200 Subject: [PATCH 06/16] filter on id --- kfet/views.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kfet/views.py b/kfet/views.py index 2fe284ad..8bca6462 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -1282,12 +1282,13 @@ def history_json(request): transfer_queryset_prefetch = Transfer.objects.select_related( 'from_acc__trigramme', 'to_acc__trigramme', + 'from_acc__id', 'to_acc__id', 'canceled_by__trigramme') if accounts: transfer_queryset_prefetch = transfer_queryset_prefetch.filter( - Q(from_acc__trigramme__in=accounts) | - Q(to_acc__trigramme__in=accounts)) + Q(from_acc__id__in=accounts) | + Q(to_acc__id__in=accounts)) if not request.user.has_perm('kfet.is_team'): acc = request.user.profile.account_kfet From 0b61a48c65765d76c0838aeaa33100914444a510 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sat, 10 Dec 2016 23:13:43 -0200 Subject: [PATCH 07/16] fix selection --- kfet/templates/kfet/history.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kfet/templates/kfet/history.html b/kfet/templates/kfet/history.html index 091b4f2f..bc12effa 100644 --- a/kfet/templates/kfet/history.html +++ b/kfet/templates/kfet/history.html @@ -142,9 +142,10 @@ $(document).ready(function() { selected: function(e, ui) { $(ui.selected).each(function() { if ($(this).hasClass('opegroup')) { - var opegroup = $(this).data('opegroup'); + var type = $(this).data('type'); + var id = $(this).data('id'); $(this).siblings('.ope').filter(function() { - return $(this).data('opegroup') == opegroup + return $(this).data(type) == id }).addClass('ui-selected'); } }); From 2c2da60e5461defa47cae6e3f394f18088df39cf Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sat, 10 Dec 2016 23:52:26 -0200 Subject: [PATCH 08/16] send data for cancel --- kfet/static/kfet/js/history.js | 10 ++++++---- kfet/templates/kfet/history.html | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/kfet/static/kfet/js/history.js b/kfet/static/kfet/js/history.js index e9486a1e..8efa120a 100644 --- a/kfet/static/kfet/js/history.js +++ b/kfet/static/kfet/js/history.js @@ -22,7 +22,6 @@ function KHistory(options={}) { $opegroup.after($ope); } } else { - $opegroup.addClass("transfergroup"); for (var i=0; i 0) confirmCancel(opes_to_cancel); From 49bef61e53b46993bab415804231895f8a5706bc Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sun, 11 Dec 2016 14:45:52 -0200 Subject: [PATCH 09/16] filter transfers frop opes --- kfet/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kfet/views.py b/kfet/views.py index 8bca6462..5fbcea3e 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -1102,7 +1102,9 @@ def kpsul_cancel_operations(request): # Checking if BAD REQUEST (opes_pk not int or not existing) try: # Set pour virer les doublons - opes_post = set(map(int, filter(None, request.POST.getlist('operations[]', [])))) + opes_post = set(map(lambda s: int(s.split()[1]), + filter(lambda s: s.split()[0] == 'ope', + request.POST.getlist('operations[]', [])))) except ValueError: return JsonResponse(data, status=400) opes_all = ( From 66304359c0f6fe6206f009f25ba6b96bc25acdd6 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sun, 11 Dec 2016 16:22:55 -0200 Subject: [PATCH 10/16] unite cancel_ope and cancel_transfer --- kfet/views.py | 97 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 27 deletions(-) diff --git a/kfet/views.py b/kfet/views.py index 5fbcea3e..32889cff 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -1097,7 +1097,7 @@ def kpsul_perform_operations(request): @teamkfet_required def kpsul_cancel_operations(request): # Pour la réponse - data = { 'canceled': [], 'warnings': {}, 'errors': {}} + data = {'canceled': {}, 'warnings': {}, 'errors': {}} # Checking if BAD REQUEST (opes_pk not int or not existing) try: @@ -1105,20 +1105,39 @@ def kpsul_cancel_operations(request): opes_post = set(map(lambda s: int(s.split()[1]), filter(lambda s: s.split()[0] == 'ope', request.POST.getlist('operations[]', [])))) + transfers_post = \ + set(map(lambda s: int(s.split()[1]), + filter(lambda s: s.split()[0] == 'transfer', + request.POST.getlist('operations[]', [])))) except ValueError: return JsonResponse(data, status=400) + opes_all = ( Operation.objects .select_related('group', 'group__on_acc', 'group__on_acc__negative') .filter(pk__in=opes_post)) opes_pk = [ ope.pk for ope in opes_all ] opes_notexisting = [ ope for ope in opes_post if ope not in opes_pk ] - if opes_notexisting: - data['errors']['opes_notexisting'] = opes_notexisting + + transfers_all = ( + Transfer.objects + .select_related('group', 'from_acc', 'from_acc__negative', + 'to_acc', 'to_acc__negative') + .filter(pk__in=transfers_post)) + transfers_pk = [transfer.pk for transfer in transfers_all] + transfers_notexisting = [transfer for transfer in transfers_post + if transfer not in transfers_pk] + + if transfers_notexisting or opes_notexisting: + if transfers_notexisting: + data['errors']['transfers_notexisting'] = transfers_notexisting + if opes_notexisting: + data['errors']['opes_notexisting'] = opes_notexisting return JsonResponse(data, status=400) - opes_already_canceled = [] # Déjà annulée - opes = [] # Pas déjà annulée + already_canceled = {} # Opération/Transfert déjà annulé + opes = [] # Pas déjà annulée + transfers = [] required_perms = set() stop_all = False cancel_duration = Settings.CANCEL_DURATION() @@ -1129,7 +1148,7 @@ def kpsul_cancel_operations(request): for ope in opes_all: if ope.canceled_at: # Opération déjà annulée, va pour un warning en Response - opes_already_canceled.append(ope.pk) + already_canceled['opes'].append(ope.pk) else: opes.append(ope.pk) # Si opé il y a plus de CANCEL_DURATION, permission requise @@ -1163,7 +1182,7 @@ def kpsul_cancel_operations(request): if not last_statement or last_statement.at < ope.group.at: if ope.type == Operation.PURCHASE: if ope.group.on_acc.is_cash: - to_checkouts_balances[ope.group.checkout] -= - ope.amount + to_checkouts_balances[ope.group.checkout] -= -ope.amount else: to_checkouts_balances[ope.group.checkout] -= ope.amount @@ -1176,22 +1195,38 @@ def kpsul_cancel_operations(request): # est recalculé automatiquement if ope.article and ope.article_nb: last_stock = (InventoryArticle.objects - .select_related('inventory') - .filter(article=ope.article) - .order_by('inventory__at') - .last()) + .select_related('inventory') + .filter(article=ope.article) + .order_by('inventory__at') + .last()) if not last_stock or last_stock.inventory.at < ope.group.at: to_articles_stocks[ope.article] += ope.article_nb - if not opes: - data['warnings']['already_canceled'] = opes_already_canceled + for transfer in transfers_all: + if transfer.canceled_at: + # Transfert déjà annulé, va pour un warning en Response + already_canceled['transfers'].append(transfer.pk) + else: + transfers.append(transfer.pk) + # Si transfer il y a plus de CANCEL_DURATION, permission requise + if transfer.group.at + cancel_duration < timezone.now(): + required_perms.add('kfet.cancel_old_operations') + + # Calcul de toutes modifs à faire en cas de validation + + # Pour les balances de comptes + to_accounts_balances[transfer.from_acc] += transfer.amount + to_accounts_balances[transfer.to_acc] += -transfer.amount + + if not opes and not transfers: + data['warnings']['already_canceled'] = already_canceled return JsonResponse(data) negative_accounts = [] # Checking permissions or stop for account in to_accounts_balances: (perms, stop) = account.perms_to_perform_operation( - amount = to_accounts_balances[account]) + amount=to_accounts_balances[account]) required_perms |= perms stop_all = stop_all or stop if stop: @@ -1211,25 +1246,31 @@ def kpsul_cancel_operations(request): with transaction.atomic(): (Operation.objects.filter(pk__in=opes) .update(canceled_by=canceled_by, canceled_at=canceled_at)) + + (Transfer.objects.filter(pk__in=transfers) + .update(canceled_by=canceled_by, canceled_at=canceled_at)) + for account in to_accounts_balances: Account.objects.filter(pk=account.pk).update( - balance = F('balance') + to_accounts_balances[account]) + balance=F('balance') + to_accounts_balances[account]) for checkout in to_checkouts_balances: Checkout.objects.filter(pk=checkout.pk).update( - balance = F('balance') + to_checkouts_balances[checkout]) + balance=F('balance') + to_checkouts_balances[checkout]) for group in to_groups_amounts: OperationGroup.objects.filter(pk=group.pk).update( - amount = F('amount') + to_groups_amounts[group]) + amount=F('amount') + to_groups_amounts[group]) for article in to_articles_stocks: Article.objects.filter(pk=article.pk).update( - stock = F('stock') + to_articles_stocks[article]) + stock=F('stock') + to_articles_stocks[article]) # Websocket data - websocket_data = { 'opegroups': [], 'opes': [], 'checkouts': [], 'articles': [] } + websocket_data = {'opegroups': [], 'opes': [], + 'checkouts': [], 'articles': []} # Need refresh from db cause we used update on querysets - opegroups_pk = [ opegroup.pk for opegroup in to_groups_amounts ] + opegroups_pk = [opegroup.pk for opegroup in to_groups_amounts] opegroups = (OperationGroup.objects - .values('id','amount','is_cof').filter(pk__in=opegroups_pk)) + .values('id', 'amount', 'is_cof') + .filter(pk__in=opegroups_pk)) for opegroup in opegroups: websocket_data['opegroups'].append({ 'cancellation': True, @@ -1246,15 +1287,16 @@ def kpsul_cancel_operations(request): 'canceled_at': canceled_at, }) # Need refresh from db cause we used update on querysets - checkouts_pk = [ checkout.pk for checkout in to_checkouts_balances] + checkouts_pk = [checkout.pk for checkout in to_checkouts_balances] checkouts = (Checkout.objects - .values('id', 'balance').filter(pk__in=checkouts_pk)) + .values('id', 'balance') + .filter(pk__in=checkouts_pk)) for checkout in checkouts: websocket_data['checkouts'].append({ 'id': checkout['id'], 'balance': checkout['balance']}) # Need refresh from db cause we used update on querysets - articles_pk = [ article.pk for articles in to_articles_stocks] + articles_pk = [article.pk for articles in to_articles_stocks] articles = Article.objects.values('id', 'stock').filter(pk__in=articles_pk) for article in articles: websocket_data['articles'].append({ @@ -1262,9 +1304,10 @@ def kpsul_cancel_operations(request): 'stock': article['stock']}) consumers.KPsul.group_send('kfet.kpsul', websocket_data) - data['canceled'] = opes - if opes_already_canceled: - data['warnings']['already_canceled'] = opes_already_canceled + data['canceled']['opes'] = opes + data['canceled']['transfers'] = transfers + if already_canceled: + data['warnings']['already_canceled'] = already_canceled return JsonResponse(data) @login_required From 1dbbad38b90144adb3e64092ac46419de253d854 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sun, 11 Dec 2016 21:00:42 -0200 Subject: [PATCH 11/16] transfer cancellation html --- kfet/static/kfet/js/history.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/kfet/static/kfet/js/history.js b/kfet/static/kfet/js/history.js index 8efa120a..7048d121 100644 --- a/kfet/static/kfet/js/history.js +++ b/kfet/static/kfet/js/history.js @@ -79,6 +79,9 @@ function KHistory(options={}) { .find('.infos1').text(transfer['from_acc']).end() .find('.infos2').text(transfer['to_acc']).end(); + if (transfer['canceled_at']) + this.cancelOpe(transfer, $transfer_html); + return $transfer_html ; } @@ -151,9 +154,9 @@ function KHistory(options={}) { }); } - this.findOpe = function(id) { + this.findOpe = function(id, type) { return this.$container.find('.ope').filter(function() { - return $(this).data('ope') == id + return ($(this).data('id') == id && $(this).data('type') == type) }); } @@ -173,6 +176,6 @@ KHistory.default_options = { template_opegroup: '
', template_transfergroup: '
', template_ope: '
', - template_transfer: '
', + template_transfer: '
', display_trigramme: true, } From 3f35dc2c06b464d5aae914912911c4295fc9cb0b Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sun, 11 Dec 2016 23:21:36 -0200 Subject: [PATCH 12/16] unite transfer history --- kfet/static/kfet/js/history.js | 1 + kfet/templates/kfet/transfers.html | 132 +++++++++++++++++------------ 2 files changed, 80 insertions(+), 53 deletions(-) diff --git a/kfet/static/kfet/js/history.js b/kfet/static/kfet/js/history.js index 7048d121..f870b4cc 100644 --- a/kfet/static/kfet/js/history.js +++ b/kfet/static/kfet/js/history.js @@ -129,6 +129,7 @@ function KHistory(options={}) { if (!this.display_trigramme) $opegroup_html.find('.trigramme').remove(); + $opegroup_html.find('.info').remove(); if (opegroup['valid_by__trigramme']) $opegroup_html.find('.valid_by').text('Par '+opegroup['valid_by__trigramme']); diff --git a/kfet/templates/kfet/transfers.html b/kfet/templates/kfet/transfers.html index cbdf0fe3..0ba0c85e 100644 --- a/kfet/templates/kfet/transfers.html +++ b/kfet/templates/kfet/transfers.html @@ -6,7 +6,11 @@ + + + + {% endblock %} {% block title %}Transferts{% endblock %} @@ -31,22 +35,7 @@

Liste des transferts

-
- {% for transfergroup in transfergroups %} -
- {{ transfergroup.at }} - {{ transfergroup.valid_by.trigramme }} - {{ transfergroup.comment }} -
- {% for transfer in transfergroup.transfers.all %} -
- {{ transfer.amount }} € - {{ transfer.from_acc.trigramme }} - - {{ transfer.to_acc.trigramme }} -
- {% endfor %} - {% endfor %} +
@@ -70,15 +59,80 @@ $(document).ready(function() { }); } + khistory = new KHistory({ + display_trigramme: false, + }); + + function getHistory() { + var data = {'transfersonly': true}; - function cancelTransfers(transfers_array, password = '') { - if (lock == 1) - return false - lock = 1; - var data = { 'transfers' : transfers_array } $.ajax({ dataType: "json", - url : "{% url 'kfet.transfers.cancel' %}", + url : "{% url 'kfet.history.json' %}", + method : "POST", + data : data, + }) + .done(function(data) { + for (var i=0; i 0) + confirmCancel(opes_to_cancel); + } + }); + + function confirmCancel(opes_to_cancel) { + var nb = opes_to_cancel.length; + var content = nb+' opération'.pluralize(nb) + +' va'.pluralize(nb, ' vont') + + ' être' + + ' annulée'.pluralize(nb); + $.confirm({ + title: 'Confirmation', + content: content, + backgroundDismiss: true, + animation: 'top', + closeAnimation: 'bottom', + keyboardEnabled: true, + confirm: function() { + cancelOperations(opes_to_cancel); + } + }); + } + + function cancelOperations(opes_array, password = '') { + if (lock == 1) + return false + lock = 1 ; + var data = { 'operations' : opes_array } + $.ajax({ + dataType: "json", + url : "{% url 'kfet.kpsul.cancel_operations' %}", method : "POST", data : data, beforeSend: function ($xhr) { @@ -89,11 +143,7 @@ $(document).ready(function() { }) .done(function(data) { - for (var i=0; i 0) - cancelTransfers(transfers_to_cancel); - } - }); + getHistory(); }); From a9e1cd01db58e1757b21aa900e709c15e109caba Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sun, 11 Dec 2016 23:22:14 -0200 Subject: [PATCH 13/16] add transfersonly option --- kfet/views.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kfet/views.py b/kfet/views.py index 32889cff..e07c962b 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -1317,6 +1317,7 @@ def history_json(request): to_date = request.POST.get('to', None) checkouts = request.POST.getlist('checkouts[]', None) accounts = request.POST.getlist('accounts[]', None) + transfers_only = request.POST.get('transfersonly', None) # Construction de la requête (sur les opérations) pour le prefetch ope_queryset_prefetch = Operation.objects.select_related( @@ -1368,6 +1369,8 @@ def history_json(request): if checkouts: opegroups = opegroups.filter(checkout_id__in=checkouts) transfergroups = TransferGroup.objects.none() + if transfers_only: + opegroups = OperationGroup.objects.none() if accounts: opegroups = opegroups.filter(on_acc_id__in=accounts) # Un non-membre de l'équipe n'a que accès à son historique From ee54b366961e873bfb7ae50b1339a773c1d82629 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sun, 11 Dec 2016 23:22:59 -0200 Subject: [PATCH 14/16] minor imprevements to history --- kfet/templates/kfet/history.html | 55 +++++++------------------------- 1 file changed, 11 insertions(+), 44 deletions(-) diff --git a/kfet/templates/kfet/history.html b/kfet/templates/kfet/history.html index 01aaa359..97a0e413 100644 --- a/kfet/templates/kfet/history.html +++ b/kfet/templates/kfet/history.html @@ -62,6 +62,8 @@ $(document).ready(function() { settings = { 'subvention_cof': parseFloat({{ settings.subvention_cof|unlocalize }})} + lock = 0 ; + khistory = new KHistory(); var $from_date = $('#from_date'); @@ -166,7 +168,10 @@ $(document).ready(function() { function confirmCancel(opes_to_cancel) { var nb = opes_to_cancel.length; - var content = nb+" opérations vont être annulées"; + var content = nb+' opération'.pluralize(nb) + +' va'.pluralize(nb, ' vont') + + ' être' + + ' annulée'.pluralize(nb); $.confirm({ title: 'Confirmation', content: content, @@ -180,50 +185,10 @@ $(document).ready(function() { }); } - function requestAuth(data, callback) { - var content = getErrorsHtml(data); - content += '', - $.confirm({ - title: 'Authentification requise', - content: content, - backgroundDismiss: true, - animation:'top', - closeAnimation:'bottom', - keyboardEnabled: true, - confirm: function() { - var password = this.$content.find('input').val(); - callback(password); - }, - onOpen: function() { - var that = this; - this.$content.find('input').on('keypress', function(e) { - if (e.keyCode == 13) - that.$confirmButton.click(); - }); - }, - }); - } - - function getErrorsHtml(data) { - var content = ''; - if ('missing_perms' in data['errors']) { - content += 'Permissions manquantes'; - content += '
    '; - for (var i=0; i'; - content += '
'; - } - if ('negative' in data['errors']) { - var url_base = "{% url 'kfet.account.update' LIQ}"; - url_base = base_url(0, url_base.length-8); - for (var i=0; iAutorisation de négatif requise pour '+data['errors']['negative'][i]+''; - } - } - return content; - } - function cancelOperations(opes_array, password = '') { + if (lock == 1) + return false + lock = 1 ; var data = { 'operations' : opes_array } $.ajax({ dataType: "json", @@ -239,6 +204,7 @@ $(document).ready(function() { }) .done(function(data) { khistory.$container.find('.ui-selected').removeClass('ui-selected'); + lock = 0 ; }) .fail(function($xhr) { var data = $xhr.responseJSON; @@ -252,6 +218,7 @@ $(document).ready(function() { displayErrors(getErrorsHtml(data)); break; } + lock = 0 ; }); } From e52c44580f4cf24c09c8ac6338ad60dd9a3f6ae8 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sun, 11 Dec 2016 23:23:12 -0200 Subject: [PATCH 15/16] pluralize function --- kfet/static/kfet/js/kfet.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kfet/static/kfet/js/kfet.js b/kfet/static/kfet/js/kfet.js index e3e5a6d9..6bb43470 100644 --- a/kfet/static/kfet/js/kfet.js +++ b/kfet/static/kfet/js/kfet.js @@ -138,3 +138,8 @@ function requestAuth(data, callback, focus_next = null) { }); } + +String.prototype.pluralize = function(count, irreg_plural = false) { + plural = irreg_plural ? irreg_plural : this + 's' ; + return (count==1 ? this : plural) ; +} From f06a732da5fdfde868b4b185c0822cdaff951a0d Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sun, 11 Dec 2016 23:29:05 -0200 Subject: [PATCH 16/16] remove unnecessary function --- kfet/urls.py | 2 -- kfet/views.py | 98 --------------------------------------------------- 2 files changed, 100 deletions(-) diff --git a/kfet/urls.py b/kfet/urls.py index 9b9ebf21..e0bacf9a 100644 --- a/kfet/urls.py +++ b/kfet/urls.py @@ -170,8 +170,6 @@ urlpatterns = [ name = 'kfet.transfers.create'), url(r'^transfers/perform$', views.perform_transfers, name = 'kfet.transfers.perform'), - url(r'^transfers/cancel$', views.cancel_transfers, - name = 'kfet.transfers.cancel'), # ----- # Inventories urls diff --git a/kfet/views.py b/kfet/views.py index e07c962b..b5ade6ae 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -1594,104 +1594,6 @@ def perform_transfers(request): return JsonResponse(data) -@teamkfet_required -def cancel_transfers(request): - # Pour la réponse - data = { 'canceled': [], 'warnings': {}, 'errors': {}} - - # Checking if BAD REQUEST (transfers_pk not int or not existing) - try: - # Set pour virer les doublons - transfers_post = set(map(int, filter(None, request.POST.getlist('transfers[]', [])))) - except ValueError: - return JsonResponse(data, status=400) - transfers_all = ( - Transfer.objects - .select_related('group', 'from_acc', 'from_acc__negative', - 'to_acc', 'to_acc__negative') - .filter(pk__in=transfers_post)) - transfers_pk = [ transfer.pk for transfer in transfers_all ] - transfers_notexisting = [ transfer for transfer in transfers_post - if transfer not in transfers_pk ] - if transfers_notexisting: - data['errors']['transfers_notexisting'] = transfers_notexisting - return JsonResponse(data, status=400) - - transfers_already_canceled = [] # Déjà annulée - transfers = [] # Pas déjà annulée - required_perms = set() - stop_all = False - cancel_duration = Settings.CANCEL_DURATION() - to_accounts_balances = defaultdict(lambda:0) # Modifs à faire sur les balances des comptes - for transfer in transfers_all: - if transfer.canceled_at: - # Transfert déjà annulé, va pour un warning en Response - transfers_already_canceled.append(transfer.pk) - else: - transfers.append(transfer.pk) - # Si transfer il y a plus de CANCEL_DURATION, permission requise - if transfer.group.at + cancel_duration < timezone.now(): - required_perms.add('kfet.cancel_old_operations') - - # Calcul de toutes modifs à faire en cas de validation - - # Pour les balances de comptes - to_accounts_balances[transfer.from_acc] += transfer.amount - to_accounts_balances[transfer.to_acc] += -transfer.amount - - if not transfers: - data['warnings']['already_canceled'] = transfers_already_canceled - return JsonResponse(data) - - negative_accounts = [] - # Checking permissions or stop - for account in to_accounts_balances: - (perms, stop) = account.perms_to_perform_operation( - amount = to_accounts_balances[account]) - required_perms |= perms - stop_all = stop_all or stop - if stop: - negative_accounts.append(account.trigramme) - - print(required_perms) - print(request.user.get_all_permissions()) - - if stop_all or not request.user.has_perms(required_perms): - missing_perms = get_missing_perms(required_perms, request.user) - if missing_perms: - data['errors']['missing_perms'] = missing_perms - if stop_all: - data['errors']['negative'] = negative_accounts - return JsonResponse(data, status=403) - - canceled_by = required_perms and request.user.profile.account_kfet or None - canceled_at = timezone.now() - - with transaction.atomic(): - (Transfer.objects.filter(pk__in=transfers) - .update(canceled_by=canceled_by, canceled_at=canceled_at)) - - for account in to_accounts_balances: - Account.objects.filter(pk=account.pk).update( - balance = F('balance') + to_accounts_balances[account]) - account.refresh_from_db() - if account.balance < 0: - if hasattr(account, 'negative'): - if not account.negative.start: - account.negative.start = timezone.now() - account.negative.save() - else: - negative = AccountNegative( - account = account, start = timezone.now()) - negative.save() - elif (hasattr(account, 'negative') - and not account.negative.balance_offset): - account.negative.delete() - - data['canceled'] = transfers - if transfers_already_canceled: - data['warnings']['already_canceled'] = transfers_already_canceled - return JsonResponse(data) class InventoryList(ListView): queryset = (Inventory.objects