From 92ec85dbbdf65e16da7595d6ae30eae8698a49d9 Mon Sep 17 00:00:00 2001 From: Hugo Manet Date: Wed, 7 Dec 2016 21:35:27 +0100 Subject: [PATCH 01/34] =?UTF-8?q?Ajout=20d'un=20.distinct()=20dans=20la=20?= =?UTF-8?q?selection=20des=20articles=20li=C3=A9s=20=C3=A0=20un=20supplier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kfet/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/kfet/views.py b/kfet/views.py index 3f1e1f4d..039aa65a 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -1679,6 +1679,7 @@ def order_create(request, pk): articles = (Article.objects .filter(suppliers=supplier.pk) + .distinct() .select_related('category') .order_by('category__name', 'name')) From 5492ecf534c6a8131ae5701b33328c56b0e7918b Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 13 Dec 2016 00:32:52 -0200 Subject: [PATCH 02/34] add ukf for price visibility --- kfet/templates/kfet/kpsul.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 88f8f2f9..47feb71b 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -563,7 +563,7 @@ $(document).ready(function() { for (var elem in article) { article_html.find('.'+elem).text(article[elem]) } - article_html.find('.price').text(amountToUKF(article['price'], false)); + article_html.find('.price').text(amountToUKF(article['price'], false)+' UKF'); var category_html = articles_container .find('#data-category-'+article['category_id']); if (category_html.length == 0) { From 437233fd1071a9e44f9da8765367389d76ceaeb7 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 13 Dec 2016 00:33:25 -0200 Subject: [PATCH 03/34] functions to change purchase amount --- kfet/templates/kfet/kpsul.html | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 47feb71b..4be8b48e 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -886,6 +886,26 @@ $(document).ready(function() { updateBasketRel(); } + function addExistingPurchase(opeindex, nb) { + type = formset_container.find("#id_form-"+opeindex+"-type").val(); + id = formset_container.find("#id_form-"+opeindex+"-article").val(); + nb_before = parseInt(formset_container.find("#id_form-"+opeindex+"-article_nb").val()); + nb_after = nb_before + nb; + if (type == 'purchase') { + if (nb_after == 0) { + deleteFromBasket(opeindex); + } else if (nb_after > 0 && nb_after <= 25) { + amountEuro_after = amountEuroPurchase(id, nb_after); + amountUKF_after = amountToUKF(amountEuro_after, account_data['is_cof']); + basket_container.find('[data-opeindex='+opeindex+']') + .find('.amount').text(amountUKF_after).end() + .find('.number').text(nb_after).end() ; + updateExistingFormset(opeindex, nb_after, amountEuro_after); + updateBasketRel(); + } + } + } + function resetBasket() { basket_container.find('tr').remove(); mngmt_total_forms = 1; @@ -1022,6 +1042,12 @@ $(document).ready(function() { formset_container.find('#id_form-'+opeindex+'-DELETE').prop('checked', true); } + function updateExistingFormset(opeindex, nb, amount) { + formset_container + .find('#id_form-'+opeindex+'-amount').val((parseFloat(amount)).toFixed(2)).end() + .find('#id_form-'+opeindex+'-article_nb').val(nb); + } + // ----- // History // ----- From 9443f86298e3316991c03d83c39c15b932c4f587 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 13 Dec 2016 01:11:35 -0200 Subject: [PATCH 04/34] use arrow keys to add/remove article --- kfet/templates/kfet/kpsul.html | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 4be8b48e..1a177dcd 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -617,8 +617,8 @@ $(document).ready(function() { var articleSelect = $('#article_autocomplete'); var articleId = $('#article_id'); var articleNb = $('#article_number'); - // 8:Backspace|9:Tab|13:Enter|46:DEL|112-117:F1-6|119-123:F8-F12 - var normalKeys = /^(8|9|13|46|112|113|114|115|116|117|119|120|121|122|123)$/; + // 8:Backspace|9:Tab|13:Enter|38-40:Arrows|46:DEL|112-117:F1-6|119-123:F8-F12 + var normalKeys = /^(8|9|13|37|38|39|40|46|112|113|114|115|116|117|119|120|121|122|123)$/; var articlesList = []; function deleteNonMatching(array, str) { @@ -818,11 +818,25 @@ $(document).ready(function() { }); $(document).on('keydown', function (e) { - if (e.keyCode == 46) { - // DEL (Suppr) - basket_container.find('.ui-selected').each(function () { - deleteFromBasket($(this).data('opeindex')); - }); + switch(e.which) { + case 46: + // DEL (Suppr) + basket_container.find('.ui-selected').each(function () { + deleteFromBasket($(this).data('opeindex')); + }); + break; + case 38: + // Arrow up + basket_container.find('.ui-selected').each(function () { + addExistingPurchase($(this).data('opeindex'), 1); + }); + break; + case 40: + // Arrow down + basket_container.find('.ui-selected').each(function () { + addExistingPurchase($(this).data('opeindex'), -1); + }); + break; } }); From 711ef7e97bfc027dcfce7061d7d6d2369f3e1c4c Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 13 Dec 2016 01:13:16 -0200 Subject: [PATCH 05/34] one line by article id --- kfet/templates/kfet/kpsul.html | 35 ++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 1a177dcd..a78028bf 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -774,16 +774,27 @@ $(document).ready(function() { } function addPurchase(id, nb) { - var amount_euro = amountEuroPurchase(id, nb).toFixed(2); - var index = addPurchaseToFormset(article_data[1], nb, amount_euro); - article_basket_html = $(item_basket_default_html); - article_basket_html - .attr('data-opeindex', index) - .find('.number').text(nb).end() - .find('.name').text(article_data[0]).end() - .find('.amount').text(amountToUKF(amount_euro, account_data['is_cof'])); - basket_container.prepend(article_basket_html); - updateBasketRel(); + var existing = false; + formset_container.find('[data-opeindex]').each(function () { + var opeindex = $(this).attr('data-opeindex'); + var article_id = $(this).find('#id_form-'+opeindex+'-article').val(); + if (article_id == id) { + existing = true ; + addExistingPurchase(opeindex, nb); + } + }); + if (!existing) { + var amount_euro = amountEuroPurchase(id, nb).toFixed(2); + var index = addPurchaseToFormset(article_data[1], nb, amount_euro); + article_basket_html = $(item_basket_default_html); + article_basket_html + .attr('data-opeindex', index) + .find('.number').text(nb).end() + .find('.name').text(article_data[0]).end() + .find('.amount').text(amountToUKF(amount_euro, account_data['is_cof'])); + basket_container.prepend(article_basket_html); + updateBasketRel(); + } } function addDeposit(amount, is_checkout=1) { @@ -903,8 +914,8 @@ $(document).ready(function() { function addExistingPurchase(opeindex, nb) { type = formset_container.find("#id_form-"+opeindex+"-type").val(); id = formset_container.find("#id_form-"+opeindex+"-article").val(); - nb_before = parseInt(formset_container.find("#id_form-"+opeindex+"-article_nb").val()); - nb_after = nb_before + nb; + nb_before = formset_container.find("#id_form-"+opeindex+"-article_nb").val(); + nb_after = parseInt(nb_before) + parseInt(nb); if (type == 'purchase') { if (nb_after == 0) { deleteFromBasket(opeindex); From 080ff0f8218d404db4d56171bdab7e0652ee654f Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 13 Dec 2016 01:41:59 -0200 Subject: [PATCH 06/34] warning if not enough stock --- kfet/static/kfet/css/kpsul.css | 5 +++++ kfet/templates/kfet/kpsul.html | 22 ++++++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/kfet/static/kfet/css/kpsul.css b/kfet/static/kfet/css/kpsul.css index 9fd53604..8e713651 100644 --- a/kfet/static/kfet/css/kpsul.css +++ b/kfet/static/kfet/css/kpsul.css @@ -383,6 +383,11 @@ input[type=number]::-webkit-outer-spin-button { color:#FFF; } +#basket tr.low-stock { + background-color:rgba(236,100,0,0.6); + color:#FFF; +} + /* History */ .kpsul_middle_right_col { diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index a78028bf..4177c16d 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -589,7 +589,7 @@ $(document).ready(function() { }); $after.after(article_html); // Pour l'autocomplétion - articlesList.push([article['name'],article['id'],article['category_id'],article['price']]); + articlesList.push([article['name'],article['id'],article['category_id'],article['price'], article['stock']]); } function getArticles() { @@ -792,11 +792,22 @@ $(document).ready(function() { .find('.number').text(nb).end() .find('.name').text(article_data[0]).end() .find('.amount').text(amountToUKF(amount_euro, account_data['is_cof'])); + if (is_low_stock(id, nb)) + article_basket_html.addClass('low-stock'); basket_container.prepend(article_basket_html); updateBasketRel(); } } + function is_low_stock(id, nb) { + var i = 0 ; + while (i= 0 && stock < nb) ; + } + function addDeposit(amount, is_checkout=1) { var deposit_basket_html = $(item_basket_default_html); var amount = parseFloat(amount).toFixed(2); @@ -922,9 +933,12 @@ $(document).ready(function() { } else if (nb_after > 0 && nb_after <= 25) { amountEuro_after = amountEuroPurchase(id, nb_after); amountUKF_after = amountToUKF(amountEuro_after, account_data['is_cof']); - basket_container.find('[data-opeindex='+opeindex+']') - .find('.amount').text(amountUKF_after).end() - .find('.number').text(nb_after).end() ; + var article_html = basket_container.find('[data-opeindex='+opeindex+']'); + article_html.find('.amount').text(amountUKF_after).end() + .find('.number').text(nb_after).end() ; + + if (is_low_stock(id, nb_after)) + article_html.addClass('low-stock'); updateExistingFormset(opeindex, nb_after, amountEuro_after); updateBasketRel(); } From 71fee9bf8a49386a7feb878fb46f40addeaddddc Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 13 Dec 2016 20:58:40 -0200 Subject: [PATCH 07/34] temporary low stock css --- kfet/static/kfet/css/kpsul.css | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/kfet/static/kfet/css/kpsul.css b/kfet/static/kfet/css/kpsul.css index 8e713651..86418d09 100644 --- a/kfet/static/kfet/css/kpsul.css +++ b/kfet/static/kfet/css/kpsul.css @@ -378,13 +378,12 @@ input[type=number]::-webkit-outer-spin-button { text-align:right; } -#basket tr.ui-selected, #basket tr.ui-selecting { - background-color:rgba(200,16,46,0.6); - color:#FFF; +#basket tr.low-stock { + background-color:rgba(236,100,0,0.4); } -#basket tr.low-stock { - background-color:rgba(236,100,0,0.6); +#basket tr.ui-selected, #basket tr.ui-selecting { + background-color:rgba(200,16,46,0.6); color:#FFF; } From b7ebf4ee1c58a99ed10cdbad3fa6883a0f54a6cf Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 13 Dec 2016 22:31:52 -0200 Subject: [PATCH 08/34] add stock to article selection --- kfet/static/kfet/css/kpsul.css | 26 ++++++++++++++++++++------ kfet/templates/kfet/kpsul.html | 7 +++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/kfet/static/kfet/css/kpsul.css b/kfet/static/kfet/css/kpsul.css index 86418d09..9e2679f9 100644 --- a/kfet/static/kfet/css/kpsul.css +++ b/kfet/static/kfet/css/kpsul.css @@ -8,7 +8,7 @@ input[type=number]::-webkit-outer-spin-button { margin: 0; } -#account, #checkout, input, #history, #basket, #basket_rel, #articles_data { +#account, #checkout, #article_selection, #history, #basket, #basket_rel, #articles_data { background:#fff; } @@ -252,7 +252,7 @@ input[type=number]::-webkit-outer-spin-button { width:100%; } -#article_selection input { +#article_selection input, #article_selection span { height:100%; float:left; border:0; @@ -263,12 +263,12 @@ input[type=number]::-webkit-outer-spin-button { font-weight:bold; } -#article_selection input+input { +#article_selection input+input #article_selection input+span { border-right:0; } #article_autocomplete { - width:90%; + width:80%; padding-left:10px; } @@ -277,14 +277,24 @@ input[type=number]::-webkit-outer-spin-button { text-align:center; } +#article_stock { + width:10%; + line-height:38px; + text-align:center; +} + @media (min-width:1200px) { #article_autocomplete { - width:92% + width:84% } #article_number { width:8%; } + + #article_stock { + width:8%; + } } /* Article data */ @@ -319,6 +329,10 @@ input[type=number]::-webkit-outer-spin-button { padding-left:20px; } +#articles_data .article.low-stock { + background:rgba(236,100,0,0.3); +} + #articles_data .article:hover { background:rgba(200,16,46,0.3); cursor:pointer; @@ -379,7 +393,7 @@ input[type=number]::-webkit-outer-spin-button { } #basket tr.low-stock { - background-color:rgba(236,100,0,0.4); + background-color:rgba(236,100,0,0.3); } #basket tr.ui-selected, #basket tr.ui-selecting { diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 4177c16d..0d7cb39c 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -122,6 +122,7 @@
+
@@ -563,6 +564,9 @@ $(document).ready(function() { for (var elem in article) { article_html.find('.'+elem).text(article[elem]) } + if (-5 <= article['stock'] && article['stock'] <= 5) { + article_html.addClass('low-stock'); + } article_html.find('.price').text(amountToUKF(article['price'], false)+' UKF'); var category_html = articles_container .find('#data-category-'+article['category_id']); @@ -617,6 +621,7 @@ $(document).ready(function() { var articleSelect = $('#article_autocomplete'); var articleId = $('#article_id'); var articleNb = $('#article_number'); + var articleStock = $('#article_stock'); // 8:Backspace|9:Tab|13:Enter|38-40:Arrows|46:DEL|112-117:F1-6|119-123:F8-F12 var normalKeys = /^(8|9|13|37|38|39|40|46|112|113|114|115|116|117|119|120|121|122|123)$/; var articlesList = []; @@ -674,6 +679,7 @@ $(document).ready(function() { if (commit) { articleId.val(articlesMatch[0][1]); articleSelect.val(articlesMatch[0][0]); + articleStock.text('/'+articlesMatch[0][4]); displayMatchedArticles(articlesList); return true; } @@ -954,6 +960,7 @@ $(document).ready(function() { articleId.val(0); articleSelect.val(''); articleNb.val(''); + articleStock.text(''); displayMatchedArticles(articlesList); } From 75be9fd2a62fbeb7a617a6e556a646ac6bdc1322 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Wed, 14 Dec 2016 23:40:23 -0200 Subject: [PATCH 09/34] display stock with mouse selection --- kfet/templates/kfet/kpsul.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 0d7cb39c..93b42b39 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -726,10 +726,15 @@ $(document).ready(function() { return $article.find('.name').text(); } + function getArticleStock($article) { + return $article.find('.stock').text(); + } + // Sélection des articles à la souris/tactile articles_container.on('click', '.article', function() { articleId.val(getArticleId($(this))); articleSelect.val(getArticleName($(this))); + articleStock.text('/'+getArticleStock($(this))); displayMatchedArticles(articlesList); goToArticleNb(); }); From 4db55efb67fc50ae64799b14d677c913b20e81cb Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Wed, 14 Dec 2016 23:40:42 -0200 Subject: [PATCH 10/34] change stock warning threshold --- kfet/templates/kfet/kpsul.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 93b42b39..f18994b4 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -816,7 +816,7 @@ $(document).ready(function() { article_data = articlesList[i]; stock = article_data[4] ; - return (stock >= 0 && stock < nb) ; + return (-5 <= stock - nb && stock - nb <= 5); } function addDeposit(amount, is_checkout=1) { From 783332bbe0f4548bedc60b4e64437f7e6054f6a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michele=20Orr=C3=B9?= Date: Mon, 19 Dec 2016 19:41:50 +0100 Subject: [PATCH 11/34] Fix #117. Not tested because there's no unittests. Reviewed by @manet. --- kfet/templates/kfet/kpsul.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 88f8f2f9..5d84b926 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -906,7 +906,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', @@ -933,7 +933,7 @@ $(document).ready(function() { function askWithdraw() { $.confirm({ title: 'Montant du retrait', - content: '', + content: '', backgroundDismiss: true, animation:'top', closeAnimation:'bottom', @@ -1097,7 +1097,7 @@ $(document).ready(function() { function askAddcost(errors = '') { $.confirm({ title: 'Majoration', - content: errors + '', + content: errors + '', backgroundDismiss: true, animation:'top', closeAnimation:'bottom', From 5784b4d20a4355dd4b4afdc28330220ec0001167 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 20 Dec 2016 01:09:22 -0200 Subject: [PATCH 12/34] change stock warning CSS for basket --- kfet/static/kfet/css/kpsul.css | 6 ++++-- kfet/templates/kfet/kpsul.html | 16 +++++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/kfet/static/kfet/css/kpsul.css b/kfet/static/kfet/css/kpsul.css index 9e2679f9..09c54845 100644 --- a/kfet/static/kfet/css/kpsul.css +++ b/kfet/static/kfet/css/kpsul.css @@ -392,8 +392,10 @@ input[type=number]::-webkit-outer-spin-button { text-align:right; } -#basket tr.low-stock { - background-color:rgba(236,100,0,0.3); +#basket tr .lowstock { + visibility:hidden; + width:20px; + padding-right:15px; } #basket tr.ui-selected, #basket tr.ui-selecting { diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index f18994b4..ca2b2436 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -767,7 +767,7 @@ $(document).ready(function() { // Basket // ----- - var item_basket_default_html = ''; + var item_basket_default_html = ''; var basket_container = $('#basket table'); var arrowKeys = /^(37|38|39|40)$/; @@ -800,11 +800,12 @@ $(document).ready(function() { article_basket_html = $(item_basket_default_html); article_basket_html .attr('data-opeindex', index) - .find('.number').text(nb).end() + .find('.number').text('('+nb+'/'+article_data[4]+')').end() .find('.name').text(article_data[0]).end() .find('.amount').text(amountToUKF(amount_euro, account_data['is_cof'])); if (is_low_stock(id, nb)) - article_basket_html.addClass('low-stock'); + article_basket_html.find('.lowstock') + .css('visibility', 'visible'); basket_container.prepend(article_basket_html); updateBasketRel(); } @@ -946,10 +947,15 @@ $(document).ready(function() { amountUKF_after = amountToUKF(amountEuro_after, account_data['is_cof']); var article_html = basket_container.find('[data-opeindex='+opeindex+']'); article_html.find('.amount').text(amountUKF_after).end() - .find('.number').text(nb_after).end() ; + .find('.number').text(nb_after+'/'+article_data[4]).end() ; if (is_low_stock(id, nb_after)) - article_html.addClass('low-stock'); + article_html.find('.lowstock') + .css('visibility', 'visible'); + else + article_html.find('.lowstock') + .css('visibility', 'hidden'); + updateExistingFormset(opeindex, nb_after, amountEuro_after); updateBasketRel(); } From e981cad4054ff37c020a2b8a9fe0b47759314f5e Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 20 Dec 2016 16:48:09 -0200 Subject: [PATCH 13/34] css tweaks --- kfet/static/kfet/css/kpsul.css | 3 +-- kfet/templates/kfet/kpsul.html | 9 +++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/kfet/static/kfet/css/kpsul.css b/kfet/static/kfet/css/kpsul.css index 09c54845..c30afd72 100644 --- a/kfet/static/kfet/css/kpsul.css +++ b/kfet/static/kfet/css/kpsul.css @@ -393,8 +393,7 @@ input[type=number]::-webkit-outer-spin-button { } #basket tr .lowstock { - visibility:hidden; - width:20px; + display:none; padding-right:15px; } diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index ca2b2436..18c92ea0 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -748,6 +748,7 @@ $(document).ready(function() { addPurchase(articleId.val(), articleNb.val()); articleSelect.val(''); articleNb.val(''); + articleStock.text(''); articleSelect.focus(); displayMatchedArticles(articlesList); return false; @@ -767,7 +768,7 @@ $(document).ready(function() { // Basket // ----- - var item_basket_default_html = ''; + var item_basket_default_html = ''; var basket_container = $('#basket table'); var arrowKeys = /^(37|38|39|40)$/; @@ -805,7 +806,7 @@ $(document).ready(function() { .find('.amount').text(amountToUKF(amount_euro, account_data['is_cof'])); if (is_low_stock(id, nb)) article_basket_html.find('.lowstock') - .css('visibility', 'visible'); + .show(); basket_container.prepend(article_basket_html); updateBasketRel(); } @@ -951,10 +952,10 @@ $(document).ready(function() { if (is_low_stock(id, nb_after)) article_html.find('.lowstock') - .css('visibility', 'visible'); + .show(); else article_html.find('.lowstock') - .css('visibility', 'hidden'); + .hide(); updateExistingFormset(opeindex, nb_after, amountEuro_after); updateBasketRel(); From 1c5c1fe94d7c4d54868f12b0c5eeffb6da11d0cf Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sat, 7 Jan 2017 12:47:43 -0200 Subject: [PATCH 14/34] can change own password --- kfet/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kfet/views.py b/kfet/views.py index 7083d489..3f5def55 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -402,7 +402,8 @@ def account_update(request, trigramme): account_form.save(data = data) # Checking perm to update password - if (request.user.has_perm('kfet.change_account_password') + if ((request.user.has_perm('kfet.change_account_password') + or request.user = account.user) and pwd_form.is_valid()): pwd = pwd_form.cleaned_data['pwd1'] pwd_sha256 = hashlib.sha256(pwd.encode('utf-8')).hexdigest() From 2a20beeb5923b0b4ee2d0e4047bbb27ef2b77507 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sat, 7 Jan 2017 13:28:53 -0200 Subject: [PATCH 15/34] pep8 --- kfet/views.py | 119 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 71 insertions(+), 48 deletions(-) diff --git a/kfet/views.py b/kfet/views.py index 3f5def55..d0319c7f 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -1,45 +1,56 @@ # -*- coding: utf-8 -*- -from __future__ import (absolute_import, division, - print_function, unicode_literals) -from builtins import * - from django.shortcuts import render, get_object_or_404, redirect -from django.core.exceptions import PermissionDenied, ValidationError +from django.core.exceptions import PermissionDenied from django.core.cache import cache from django.views.generic import ListView, DetailView -from django.views.generic.edit import CreateView, UpdateView, DeleteView, FormView +from django.views.generic.edit import CreateView, UpdateView from django.core.urlresolvers import reverse_lazy from django.contrib import messages from django.contrib.messages.views import SuccessMessageMixin from django.contrib.auth import authenticate, login from django.contrib.auth.decorators import login_required, permission_required 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.http import JsonResponse, Http404 +from django.forms import formset_factory +from django.db import transaction +from django.db.models import F, Sum, Prefetch, Count from django.db.models.functions import Coalesce from django.utils import timezone from django.utils.crypto import get_random_string from gestioncof.models import CofProfile, Clipper from kfet.decorators import teamkfet_required -from kfet.models import (Account, Checkout, Article, Settings, AccountNegative, +from kfet.models import ( + Account, Checkout, Article, Settings, AccountNegative, CheckoutStatement, GenericTeamToken, Supplier, SupplierArticle, Inventory, - InventoryArticle, Order, OrderArticle) -from kfet.forms import * + InventoryArticle, Order, OrderArticle, Operation, OperationGroup, + TransferGroup, Transfer) +from kfet.forms import ( + AccountTriForm, AccountBalanceForm, AccountNoTriForm, UserForm, CofForm, + UserRestrictTeamForm, UserGroupForm, AccountForm, CofRestrictForm, + AccountPwdForm, AccountNegativeForm, UserRestrictForm, AccountRestrictForm, + GroupForm, CheckoutForm, CheckoutRestrictForm, CheckoutStatementCreateForm, + CheckoutStatementUpdateForm, ArticleForm, ArticleRestrictForm, + KPsulOperationGroupForm, KPsulAccountForm, KPsulCheckoutForm, + KPsulOperationFormSet, AddcostForm, FilterHistoryForm, SettingsForm, + TransferFormSet, InventoryArticleForm, OrderArticleForm, + OrderArticleToInventoryForm + ) from collections import defaultdict from kfet import consumers from datetime import timedelta +from decimal import Decimal import django_cas_ng import hashlib import heapq import statistics + @login_required def home(request): return render(request, "kfet/base.html") + @teamkfet_required def login_genericteam(request): # Check si besoin de déconnecter l'utilisateur de CAS @@ -345,6 +356,7 @@ def account_read(request, trigramme): # Account - Update + @login_required def account_update(request, trigramme): account = get_object_or_404(Account, trigramme=trigramme) @@ -355,39 +367,43 @@ def account_update(request, trigramme): raise PermissionDenied if request.user.has_perm('kfet.is_team'): - user_form = UserRestrictTeamForm(instance=account.user) - group_form = UserGroupForm(instance=account.user) + user_form = UserRestrictTeamForm(instance=account.user) + group_form = UserGroupForm(instance=account.user) account_form = AccountForm(instance=account) - cof_form = CofRestrictForm(instance=account.cofprofile) - pwd_form = AccountPwdForm() + cof_form = CofRestrictForm(instance=account.cofprofile) + pwd_form = AccountPwdForm() if account.balance < 0 and not hasattr(account, 'negative'): - AccountNegative.objects.create(account=account, start=timezone.now()) + AccountNegative.objects.create(account=account, + start=timezone.now()) account.refresh_from_db() if hasattr(account, 'negative'): negative_form = AccountNegativeForm(instance=account.negative) else: negative_form = None else: - user_form = UserRestrictForm(instance=account.user) + user_form = UserRestrictForm(instance=account.user) account_form = AccountRestrictForm(instance=account) - cof_form = None - group_form = None + cof_form = None + group_form = None negative_form = None - pwd_form = None + pwd_form = None if request.method == "POST": # Update attempt - success = False + success = False missing_perm = True if request.user.has_perm('kfet.is_team'): account_form = AccountForm(request.POST, instance=account) - cof_form = CofRestrictForm(request.POST, instance=account.cofprofile) - user_form = UserRestrictTeamForm(request.POST, instance=account.user) - group_form = UserGroupForm(request.POST, instance=account.user) - pwd_form = AccountPwdForm(request.POST) + cof_form = CofRestrictForm(request.POST, + instance=account.cofprofile) + user_form = UserRestrictTeamForm(request.POST, + instance=account.user) + group_form = UserGroupForm(request.POST, instance=account.user) + pwd_form = AccountPwdForm(request.POST) if hasattr(account, 'negative'): - negative_form = AccountNegativeForm(request.POST, instance=account.negative) + negative_form = AccountNegativeForm(request.POST, + instance=account.negative) if (request.user.has_perm('kfet.change_account') and account_form.is_valid() and cof_form.is_valid() @@ -399,16 +415,16 @@ def account_update(request, trigramme): put_cleaned_data_in_dict(data, cof_form) # Updating - account_form.save(data = data) + account_form.save(data=data) # Checking perm to update password - if ((request.user.has_perm('kfet.change_account_password') - or request.user = account.user) + if (request.user.has_perm('kfet.change_account_password') and pwd_form.is_valid()): pwd = pwd_form.cleaned_data['pwd1'] - pwd_sha256 = hashlib.sha256(pwd.encode('utf-8')).hexdigest() + pwd_sha256 = hashlib.sha256(pwd.encode('utf-8'))\ + .hexdigest() Account.objects.filter(pk=account.pk).update( - password = pwd_sha256) + password=pwd_sha256) messages.success(request, 'Mot de passe mis à jour') # Checking perm to manage perms @@ -422,21 +438,26 @@ def account_update(request, trigramme): if account.negative.balance_offset: balance_offset_old = account.negative.balance_offset if (hasattr(account, 'negative') - and request.user.has_perm('kfet.change_accountnegative') + and request.user.has_perm('kfet.change_accountnegative') and negative_form.is_valid()): - balance_offset_new = negative_form.cleaned_data['balance_offset'] + balance_offset_new = \ + negative_form.cleaned_data['balance_offset'] if not balance_offset_new: balance_offset_new = 0 - balance_offset_diff = balance_offset_new - balance_offset_old + balance_offset_diff = (balance_offset_new + - balance_offset_old) Account.objects.filter(pk=account.pk).update( - balance = F('balance') + balance_offset_diff) + balance=F('balance') + balance_offset_diff) negative_form.save() - if not balance_offset_new and Account.objects.get(pk=account.pk).balance >= 0: + if Account.objects.get(pk=account.pk).balance >= 0 \ + and not balance_offset_new: AccountNegative.objects.get(account=account).delete() success = True - messages.success(request, - 'Informations du compte %s mises à jour' % account.trigramme) + messages.success( + request, + 'Informations du compte %s mises à jour' + % account.trigramme) if request.user == account.user: missing_perm = False @@ -448,23 +469,25 @@ def account_update(request, trigramme): user_form.save() account_form.save() success = True - messages.success(request, 'Vos informations ont été mises à jour') + messages.success(request, + 'Vos informations ont été mises à jour') if missing_perm: messages.error(request, 'Permission refusée') if success: return redirect('kfet.account.read', account.trigramme) else: - messages.error(request, 'Informations non mises à jour. Corrigez les erreurs') + messages.error( + request, 'Informations non mises à jour. Corrigez les erreurs') return render(request, "kfet/account_update.html", { - 'account' : account, - 'account_form' : account_form, - 'cof_form' : cof_form, - 'user_form' : user_form, - 'group_form' : group_form, + 'account': account, + 'account_form': account_form, + 'cof_form': cof_form, + 'user_form': user_form, + 'group_form': group_form, 'negative_form': negative_form, - 'pwd_form' : pwd_form, + 'pwd_form': pwd_form, }) @permission_required('kfet.manage_perms') From fcf76b4af87794ddf33f07d5e65be45604761cf5 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sat, 7 Jan 2017 13:32:05 -0200 Subject: [PATCH 16/34] can change own password (actually working now) --- kfet/views.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/kfet/views.py b/kfet/views.py index d0319c7f..c0f90034 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -464,6 +464,7 @@ def account_update(request, trigramme): account.refresh_from_db() user_form = UserRestrictForm(request.POST, instance=account.user) account_form = AccountRestrictForm(request.POST, instance=account) + pwd_form = AccountPwdForm(request.POST) if user_form.is_valid() and account_form.is_valid(): user_form.save() @@ -472,6 +473,15 @@ def account_update(request, trigramme): messages.success(request, 'Vos informations ont été mises à jour') + if pwd_form.is_valid(): + pwd = pwd_form.cleaned_data['pwd1'] + pwd_sha256 = hashlib.sha256(pwd.encode('utf-8'))\ + .hexdigest() + Account.objects.filter(pk=account.pk).update( + password=pwd_sha256) + messages.success( + request, 'Votre mot de passe a été mis à jour') + if missing_perm: messages.error(request, 'Permission refusée') if success: From 7dc7d57a5eabf8d9e1ba9c441afe824292e2c4a8 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sat, 7 Jan 2017 13:57:54 -0200 Subject: [PATCH 17/34] restrict to team even if malicious POST edit --- kfet/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kfet/views.py b/kfet/views.py index c0f90034..0a8771d7 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -473,7 +473,8 @@ def account_update(request, trigramme): messages.success(request, 'Vos informations ont été mises à jour') - if pwd_form.is_valid(): + if request.user.has_perm('kfet.is_team') \ + and pwd_form.is_valid(): pwd = pwd_form.cleaned_data['pwd1'] pwd_sha256 = hashlib.sha256(pwd.encode('utf-8'))\ .hexdigest() From 6315ddf6b8e3c048f1b62a78c08a80d56f856440 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 10 Jan 2017 12:58:35 -0200 Subject: [PATCH 18/34] move pwd change to method Signed-off-by: Ludovic Stephan --- kfet/models.py | 7 +++++++ kfet/views.py | 11 +++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/kfet/models.py b/kfet/models.py index 419cd0a0..bf47356c 100644 --- a/kfet/models.py +++ b/kfet/models.py @@ -154,6 +154,7 @@ class Account(models.Model): # - Enregistre User, CofProfile à partir de "data" # - Enregistre Account def save(self, data = {}, *args, **kwargs): + if self.pk and data: # Account update @@ -200,6 +201,12 @@ class Account(models.Model): self.cofprofile = cof super(Account, self).save(*args, **kwargs) + def change_pwd(self, pwd): + pwd_sha256 = hashlib.sha256(pwd.encode('utf-8'))\ + .hexdigest() + self.password = pwd_sha256 + self.save() + # Surcharge de delete # Pas de suppression possible # Cas à régler plus tard diff --git a/kfet/views.py b/kfet/views.py index 0a8771d7..0f706085 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -421,10 +421,7 @@ def account_update(request, trigramme): if (request.user.has_perm('kfet.change_account_password') and pwd_form.is_valid()): pwd = pwd_form.cleaned_data['pwd1'] - pwd_sha256 = hashlib.sha256(pwd.encode('utf-8'))\ - .hexdigest() - Account.objects.filter(pk=account.pk).update( - password=pwd_sha256) + account.change_pwd(pwd) messages.success(request, 'Mot de passe mis à jour') # Checking perm to manage perms @@ -459,6 +456,7 @@ def account_update(request, trigramme): 'Informations du compte %s mises à jour' % account.trigramme) + # Modification de ses propres informations if request.user == account.user: missing_perm = False account.refresh_from_db() @@ -476,10 +474,7 @@ def account_update(request, trigramme): if request.user.has_perm('kfet.is_team') \ and pwd_form.is_valid(): pwd = pwd_form.cleaned_data['pwd1'] - pwd_sha256 = hashlib.sha256(pwd.encode('utf-8'))\ - .hexdigest() - Account.objects.filter(pk=account.pk).update( - password=pwd_sha256) + account.change_pwd(pwd) messages.success( request, 'Votre mot de passe a été mis à jour') From fabd0949e2f08e2b36e2244133a0a63682448e11 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 10 Jan 2017 15:15:53 -0200 Subject: [PATCH 19/34] correct imports Signed-off-by: Ludovic Stephan --- kfet/models.py | 1 + kfet/views.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/kfet/models.py b/kfet/models.py index bf47356c..80ee1441 100644 --- a/kfet/models.py +++ b/kfet/models.py @@ -18,6 +18,7 @@ from django.db.models import F from django.core.cache import cache from datetime import date, timedelta import re +import hashlib def choices_length(choices): return reduce(lambda m, choice: max(m, len(choice[0])), choices, 0) diff --git a/kfet/views.py b/kfet/views.py index 0f706085..52386ca9 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -41,7 +41,6 @@ from kfet import consumers from datetime import timedelta from decimal import Decimal import django_cas_ng -import hashlib import heapq import statistics From a400832c6d42fdb25652473c471698b5aa08416f Mon Sep 17 00:00:00 2001 From: Qwann Date: Tue, 31 Jan 2017 15:55:38 +0100 Subject: [PATCH 20/34] fixing stock update --- kfet/templates/kfet/kpsul.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 70cf4ba9..862ff20c 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -1251,7 +1251,7 @@ $(document).ready(function() { } for (var i=0; i Date: Tue, 31 Jan 2017 15:55:38 +0100 Subject: [PATCH 21/34] fixes #127 fixing stock update --- kfet/templates/kfet/kpsul.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 70cf4ba9..862ff20c 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -1251,7 +1251,7 @@ $(document).ready(function() { } for (var i=0; i Date: Tue, 31 Jan 2017 16:35:52 -0200 Subject: [PATCH 22/34] fixes #87 --- kfet/forms.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) 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'] From bc14205d29bb5ed8c80ff285589eba4ea8304dd4 Mon Sep 17 00:00:00 2001 From: Qwann Date: Wed, 1 Feb 2017 19:32:18 +0100 Subject: [PATCH 23/34] fixing decimal issue2 --- kfet/templatetags/kfet_tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kfet/templatetags/kfet_tags.py b/kfet/templatetags/kfet_tags.py index 59840b27..2dd704b6 100644 --- a/kfet/templatetags/kfet_tags.py +++ b/kfet/templatetags/kfet_tags.py @@ -40,6 +40,6 @@ def highlight_clipper(clipper, q): @register.filter() def ukf(balance, is_cof): - grant = is_cof and (1 + Settings.SUBVENTION_COF() / 100) or 1 + grant = 1 + float(Settings.SUBVENTION_COF()) / 100 if is_cof else 1. # float nécessaire car sinon problème avec le round de future.builtins return floor(float(balance) * 10 * grant) From 44202811ae09e118482db18092b435504ef8dac4 Mon Sep 17 00:00:00 2001 From: Qwann Date: Sun, 5 Feb 2017 22:39:20 +0100 Subject: [PATCH 24/34] not supporting future.builtins anymore in templatetags --- kfet/templatetags/kfet_tags.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kfet/templatetags/kfet_tags.py b/kfet/templatetags/kfet_tags.py index 2dd704b6..3b1bb639 100644 --- a/kfet/templatetags/kfet_tags.py +++ b/kfet/templatetags/kfet_tags.py @@ -40,6 +40,5 @@ def highlight_clipper(clipper, q): @register.filter() def ukf(balance, is_cof): - grant = 1 + float(Settings.SUBVENTION_COF()) / 100 if is_cof else 1. - # float nécessaire car sinon problème avec le round de future.builtins - return floor(float(balance) * 10 * grant) + grant = is_cof and (1 + Settings.SUBVENTION_COF() / 100) or 1 + return floor(balance * 10 * grant) From 2394a5e5d2e7ecb9457d52cefe4eeb3db69fe70a Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sun, 5 Feb 2017 21:38:13 -0200 Subject: [PATCH 25/34] add low stock css to WS --- kfet/templates/kfet/kpsul.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 3fba824d..103dcc62 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -1335,6 +1335,8 @@ $(document).ready(function() { } for (var i=0; i Date: Mon, 6 Feb 2017 16:42:19 -0200 Subject: [PATCH 26/34] Corrige l'affichage du prix fixes #128 --- kfet/static/kfet/js/kfet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kfet/static/kfet/js/kfet.js b/kfet/static/kfet/js/kfet.js index 31758c36..e3e5a6d9 100644 --- a/kfet/static/kfet/js/kfet.js +++ b/kfet/static/kfet/js/kfet.js @@ -39,7 +39,7 @@ function amountDisplay(amount, is_cof=false, tri='') { function amountToUKF(amount, is_cof=false) { var coef_cof = is_cof ? 1 + settings['subvention_cof'] / 100 : 1; - return Math.floor(amount * coef_cof * 10); + return Math.round(amount * coef_cof * 10); } function isValidTrigramme(trigramme) { From 99d04fb75e631681ced95fa8484d1a445887f970 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sun, 12 Feb 2017 11:02:54 -0200 Subject: [PATCH 27/34] bugfix --- kfet/templates/kfet/kpsul.html | 47 ++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 103dcc62..636a755d 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -989,27 +989,39 @@ $(document).ready(function() { } function addExistingPurchase(opeindex, nb) { - type = formset_container.find("#id_form-"+opeindex+"-type").val(); - id = formset_container.find("#id_form-"+opeindex+"-article").val(); - nb_before = formset_container.find("#id_form-"+opeindex+"-article_nb").val(); - nb_after = parseInt(nb_before) + parseInt(nb); + var type = formset_container.find("#id_form-"+opeindex+"-type").val(); + var id = formset_container.find("#id_form-"+opeindex+"-article").val(); + var nb_before = formset_container.find("#id_form-"+opeindex+"-article_nb").val(); + var nb_after = parseInt(nb_before) + parseInt(nb); + var amountEuro_after = amountEuroPurchase(id, nb_after); + var amountUKF_after = amountToUKF(amountEuro_after, account_data['is_cof']); + if (type == 'purchase') { if (nb_after == 0) { deleteFromBasket(opeindex); } else if (nb_after > 0 && nb_after <= 25) { - amountEuro_after = amountEuroPurchase(id, nb_after); - amountUKF_after = amountToUKF(amountEuro_after, account_data['is_cof']); - var article_html = basket_container.find('[data-opeindex='+opeindex+']'); - article_html.find('.amount').text(amountUKF_after).end() - .find('.number').text(nb_after+'/'+article_data[4]).end() ; + if (nb_before > 0) { + var article_html = basket_container.find('[data-opeindex='+opeindex+']'); + article_html.find('.amount').text(amountUKF_after).end() + .find('.number').text(nb_after+'/'+article_data[4]).end() ; - if (is_low_stock(id, nb_after)) - article_html.find('.lowstock') - .show(); - else - article_html.find('.lowstock') - .hide(); + } else { + article_html = $(item_basket_default_html); + article_html + .attr('data-opeindex', opeindex) + .find('.number').text('('+nb_after+'/'+article_data[4]+')').end() + .find('.name').text(article_data[0]).end() + .find('.amount').text(amountUKF_after); + basket_container.prepend(article_basket_html); + } + + if (is_low_stock(id, nb_after)) + article_html.find('.lowstock') + .show(); + else + article_html.find('.lowstock') + .hide(); updateExistingFormset(opeindex, nb_after, amountEuro_after); updateBasketRel(); } @@ -1150,13 +1162,14 @@ $(document).ready(function() { } function deleteFromFormset(opeindex) { - formset_container.find('#id_form-'+opeindex+'-DELETE').prop('checked', true); + updateExistingFormset(opeindex, 0, '0.00'); } function updateExistingFormset(opeindex, nb, amount) { formset_container .find('#id_form-'+opeindex+'-amount').val((parseFloat(amount)).toFixed(2)).end() - .find('#id_form-'+opeindex+'-article_nb').val(nb); + .find('#id_form-'+opeindex+'-article_nb').val(nb).end() + .find('#id_form-'+opeindex+'-DELETE').prop('checked', !nb); } // ----- From 031b992fa3b8dd0c899830ff75eee50e9476be3b Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sun, 12 Feb 2017 11:09:03 -0200 Subject: [PATCH 28/34] fix brackets & lowstock indication --- kfet/templates/kfet/kpsul.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 636a755d..d5ca2810 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -857,10 +857,10 @@ $(document).ready(function() { .find('.number').text('('+nb+'/'+article_data[4]+')').end() .find('.name').text(article_data[0]).end() .find('.amount').text(amountToUKF(amount_euro, account_data['is_cof'])); + basket_container.prepend(article_basket_html); if (is_low_stock(id, nb)) article_basket_html.find('.lowstock') .show(); - basket_container.prepend(article_basket_html); updateBasketRel(); } } @@ -1003,7 +1003,7 @@ $(document).ready(function() { if (nb_before > 0) { var article_html = basket_container.find('[data-opeindex='+opeindex+']'); article_html.find('.amount').text(amountUKF_after).end() - .find('.number').text(nb_after+'/'+article_data[4]).end() ; + .find('.number').text('('+nb_after+'/'+article_data[4]+')').end() ; } else { article_html = $(item_basket_default_html); From 3fa0e4de6c083db2793f2250cedbfec987f0dc32 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sun, 12 Feb 2017 19:05:41 -0200 Subject: [PATCH 29/34] different rounding for accounts --- kfet/static/kfet/js/kfet.js | 5 +++-- kfet/templates/kfet/kpsul.html | 16 ++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/kfet/static/kfet/js/kfet.js b/kfet/static/kfet/js/kfet.js index e3e5a6d9..bab21c12 100644 --- a/kfet/static/kfet/js/kfet.js +++ b/kfet/static/kfet/js/kfet.js @@ -37,9 +37,10 @@ function amountDisplay(amount, is_cof=false, tri='') { return amountToUKF(amount, is_cof); } -function amountToUKF(amount, is_cof=false) { +function amountToUKF(amount, is_cof=false, account=false) { + var rounding = account ? Math.floor : Math.round ; var coef_cof = is_cof ? 1 + settings['subvention_cof'] / 100 : 1; - return Math.round(amount * coef_cof * 10); + return rounding(amount * coef_cof * 10); } function isValidTrigramme(trigramme) { diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index fb59060b..e064a10c 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -221,7 +221,7 @@ $(document).ready(function() { function displayAccountData() { var balance = account_data['trigramme'] != 'LIQ' ? account_data['balance'] : ''; if (balance != '') - balance = amountToUKF(account_data['balance'], account_data['is_cof']); + balance = amountToUKF(account_data['balance'], account_data['is_cof'], true); var is_cof = account_data['trigramme'] ? account_data['is_cof'] : ''; if (is_cof !== '') is_cof = is_cof ? 'COF' : 'Non-COF'; @@ -616,7 +616,7 @@ $(document).ready(function() { for (var elem in article) { article_html.find('.'+elem).text(article[elem]) } - article_html.find('.price').text(amountToUKF(article['price'], false)); + article_html.find('.price').text(amountToUKF(article['price'], false, false)); var category_html = articles_container .find('#data-category-'+article['category_id']); if (category_html.length == 0) { @@ -834,7 +834,7 @@ $(document).ready(function() { .attr('data-opeindex', index) .find('.number').text(nb).end() .find('.name').text(article_data[0]).end() - .find('.amount').text(amountToUKF(amount_euro, account_data['is_cof'])); + .find('.amount').text(amountToUKF(amount_euro, account_data['is_cof'], false)); basket_container.prepend(article_basket_html); updateBasketRel(); } @@ -848,7 +848,7 @@ $(document).ready(function() { .attr('data-opeindex', index) .find('.number').text(amount+"€").end() .find('.name').text(text).end() - .find('.amount').text(amountToUKF(amount, account_data['is_cof'])); + .find('.amount').text(amountToUKF(amount, account_data['is_cof'], false)); basket_container.prepend(deposit_basket_html); updateBasketRel(); } @@ -861,7 +861,7 @@ $(document).ready(function() { .attr('data-opeindex', index) .find('.number').text(amount+"€").end() .find('.name').text('Retrait').end() - .find('.amount').text(amountToUKF(amount, account_data['is_cof'])); + .find('.amount').text(amountToUKF(amount, account_data['is_cof'], false)); basket_container.prepend(withdraw_basket_html); updateBasketRel(); } @@ -903,7 +903,7 @@ $(document).ready(function() { var amount = $(this).find('#id_form-'+opeindex+'-amount'); if (!deleted && type == "purchase") amount.val(amountEuroPurchase(article_id, article_nb)); - basket_container.find('[data-opeindex='+opeindex+'] .amount').text(amountToUKF(amount.val(), account_data['is_cof'])); + basket_container.find('[data-opeindex='+opeindex+'] .amount').text(amountToUKF(amount.val(), account_data['is_cof'], false)); }); } @@ -922,9 +922,9 @@ $(document).ready(function() { basketrel_html += '
Sur 20€: '+ (20-amount).toFixed(2) +' €
'; } else if (account_data['trigramme'] != '' && !isBasketEmpty()) { var amount = getAmountBasket(); - var amountUKF = amountToUKF(amount, account_data['is_cof']); + var amountUKF = amountToUKF(amount, account_data['is_cof'], false); var newBalance = account_data['balance'] + amount; - var newBalanceUKF = amountToUKF(newBalance, account_data['is_cof']); + var newBalanceUKF = amountToUKF(newBalance, account_data['is_cof'], true); basketrel_html += '
Total: '+amountUKF+'
'; basketrel_html += '
Nouveau solde: '+newBalanceUKF+'
'; if (newBalance < 0) From 46e9e82da8e0093b643eeeaff1319001a45ea6e9 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Mon, 13 Feb 2017 12:19:47 -0200 Subject: [PATCH 30/34] move account save --- kfet/models.py | 1 - kfet/views.py | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/kfet/models.py b/kfet/models.py index 80ee1441..035d45f6 100644 --- a/kfet/models.py +++ b/kfet/models.py @@ -206,7 +206,6 @@ class Account(models.Model): pwd_sha256 = hashlib.sha256(pwd.encode('utf-8'))\ .hexdigest() self.password = pwd_sha256 - self.save() # Surcharge de delete # Pas de suppression possible diff --git a/kfet/views.py b/kfet/views.py index 52386ca9..44d2a991 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -396,12 +396,12 @@ def account_update(request, trigramme): account_form = AccountForm(request.POST, instance=account) cof_form = CofRestrictForm(request.POST, instance=account.cofprofile) - user_form = UserRestrictTeamForm(request.POST, + user_form = UserRestrictTeamForm(request.POST, instance=account.user) group_form = UserGroupForm(request.POST, instance=account.user) pwd_form = AccountPwdForm(request.POST) if hasattr(account, 'negative'): - negative_form = AccountNegativeForm(request.POST, + negative_form = AccountNegativeForm(request.POST, instance=account.negative) if (request.user.has_perm('kfet.change_account') @@ -421,6 +421,7 @@ def account_update(request, trigramme): and pwd_form.is_valid()): pwd = pwd_form.cleaned_data['pwd1'] account.change_pwd(pwd) + account.save() messages.success(request, 'Mot de passe mis à jour') # Checking perm to manage perms @@ -474,6 +475,7 @@ def account_update(request, trigramme): and pwd_form.is_valid(): pwd = pwd_form.cleaned_data['pwd1'] account.change_pwd(pwd) + account.save() messages.success( request, 'Votre mot de passe a été mis à jour') From 1c90608f6d361c5350688651672fff4d1000a4e9 Mon Sep 17 00:00:00 2001 From: Qwann Date: Wed, 15 Feb 2017 14:21:00 +0100 Subject: [PATCH 31/34] some cleaning --- kfet/models.py | 2 +- kfet/statistic.py | 10 ++-- kfet/tests.py | 141 +--------------------------------------------- kfet/views.py | 2 +- 4 files changed, 8 insertions(+), 147 deletions(-) diff --git a/kfet/models.py b/kfet/models.py index 88626729..2594282d 100644 --- a/kfet/models.py +++ b/kfet/models.py @@ -557,7 +557,7 @@ class Operation(models.Model): templates = { self.PURCHASE: "{nb} {article.name} ({amount}€)", self.DEPOSIT: "charge ({amount})", - self.WITHDRAW: "retrait ({amount})", + self.WITHDRAW: "retrait ({amount})", self.INITIAL: "initial ({amount})", } return templates[self.type].format(nb=self.article_nb, diff --git a/kfet/statistic.py b/kfet/statistic.py index e3c89a6d..dc329a0c 100644 --- a/kfet/statistic.py +++ b/kfet/statistic.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from django.utils import timezone +from django.db.models import Sum # donne le nom des jours d'une liste de dates @@ -28,6 +29,7 @@ def monthnames(dates): names[i] = dates[i].strftime("%B") return names + # rend les dates des nb derniers jours # dans l'ordre chronologique # aujourd'hui compris @@ -55,7 +57,7 @@ def lastmonths(nb): this_year = first_month_day.year this_month = first_month_day.month for i in range(1, nb+1): - month = ((this_month - 1 - (nb - i)) % 12) + 1 + month = ((this_month - 1 - (nb - i)) % 12) + 1 year = this_year + (nb - i) // 12 first_days[i] = timezone.datetime(year=year, month=month, @@ -91,7 +93,5 @@ def this_morning(): # Étant donné un queryset d'operations # rend la somme des article_nb def tot_ventes(queryset): - res = 0 - for op in queryset: - res += op.article_nb - return res + res = queryset.aggregate(Sum('article_nb'))['article_nb__sum'] + return res and res or 0 diff --git a/kfet/tests.py b/kfet/tests.py index 98558001..5bea7afa 100644 --- a/kfet/tests.py +++ b/kfet/tests.py @@ -2,143 +2,4 @@ from django.test import TestCase -from kfet.models import Account -from gestioncof.models import CofProfile, User - - - -names = ['Abelardus', - 'Abrahamus', - 'Acacius', - 'Accius', - 'Achaicus', - 'Achill', - 'Achilles', - 'Achilleus', - 'Acrisius', - 'Actaeon', - 'Acteon', - 'Adalricus', - 'Adelfonsus', - 'Adelphus', - 'Adeodatus', - 'Adolfus', - 'Adolphus', - 'Adrastus', - 'Adrianus', - 'Ægidius', - 'Ælia', - 'Ælianus', - 'Æmilianus', - 'Æmilius', - 'Aeneas', - 'Æolus', - 'Æschylus', - 'Æson', - 'Æsop', - 'Æther', - 'Ætius', - 'Agapetus', - 'Agapitus', - 'Agapius', - 'Agathangelus', - 'Aigidius', - 'Aiolus', - 'Ajax', - 'Alair', - 'Alaricus', - 'Albanus', - 'Alberic', - 'Albericus', - 'Albertus', - 'Albinus', - 'Albus', - 'Alcaeus', - 'Alcander', - 'Alcimus', - 'Alcinder', - 'Alerio', - 'Alexandrus', - 'Alexis', - 'Alexius', - 'Alexus', - 'Alfonsus', - 'Alfredus', - 'Almericus', - 'Aloisius', - 'Aloysius', - 'Alphaeus', - 'Alpheaus', - 'Alpheus', - 'Alphoeus', - 'Alphonsus', - 'Alphonzus', - 'Alvinius', - 'Alvredus', - 'Amadeus', - 'Amaliricus', - 'Amandus', - 'Amantius', - 'Amarandus', - 'Amaranthus', - 'Amatus', - 'Ambrosianus', - 'Ambrosius', - 'Amedeus', - 'Americus', - 'Amlethus', - 'Amletus', - 'Amor', - 'Ampelius', - 'Amphion', - 'Anacletus', - 'Anastasius', - 'Anastatius', - 'Anastius', - 'Anatolius', - 'Androcles', - 'Andronicus', - 'Anencletus', - 'Angelicus', - 'Angelus', - 'Anicetus', - 'Antigonus', - 'Antipater', - 'Antoninus', - 'Antonius', - 'Aphrodisius', - 'Apollinaris'] - - -# Ne pas supprimer, peut être utile pour regénérer -# d'autres fixtures à l'avenir -class TestFoo(TestCase): - fixtures = ['users', 'sites', 'gestion', 'articles'] - - def test_foo(self): - pass - # for name in names: - # user = User(username=name, - # last_name='Romain', - # first_name=name) - # user.email = '{}.{}@ens.fr'.format(user.first_name, user.last_name) - # user.save() - - # galois_trigrammes = map('{:03d}'.format, range(40)) - # galois = CofProfile.objects.filter(user__last_name='Gaulois') - - # romains_trigrammes = map(lambda x: str(100+x), range(40)) - # romains = CofProfile.objects.filter(user__last_name='Romain') - - # for t, c in zip(galois_trigrammes, galois): - # Account.objects.create(cofprofile=c, trigramme=t) - # for t, c in zip(romains_trigrammes, romains): - # Account.objects.create(cofprofile=c, trigramme=t) - - -# class TestBar(TestCase): -# fixtures = ['users', 'sites', 'gestion', 'articles', 'groups', 'accounts'] - - -# def test_foo(self): -# pass +# Écrire les tests ici diff --git a/kfet/views.py b/kfet/views.py index 24fa8c0d..586f3d8b 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -2020,7 +2020,7 @@ class ObjectResumeStat(DetailView): """ template_name = 'kfet/object_stat_resume.html' context_object_name = '' - id_prefix = 'id_a_definir' + id_prefix = '' # nombre de vues à résumer nb_stat = 2 # Le combienième est celui par defaut ? From 46f343b1ab888a4291f7ef7ed869709d3872e53e Mon Sep 17 00:00:00 2001 From: Qwann Date: Wed, 15 Feb 2017 14:44:58 +0100 Subject: [PATCH 32/34] =?UTF-8?q?la=20K-F=C3=AAt=20se=20r=C3=A9veille=20?= =?UTF-8?q?=C3=A0=207h?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kfet/statistic.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/kfet/statistic.py b/kfet/statistic.py index dc329a0c..09f9e935 100644 --- a/kfet/statistic.py +++ b/kfet/statistic.py @@ -2,6 +2,7 @@ from django.utils import timezone from django.db.models import Sum +KFET_WAKES_UP_AT = 7 # donne le nom des jours d'une liste de dates # dans un dico ordonné @@ -61,7 +62,8 @@ def lastmonths(nb): year = this_year + (nb - i) // 12 first_days[i] = timezone.datetime(year=year, month=month, - day=1) + day=1, + hour=KFET_WAKES_UP_AT) return first_days @@ -69,7 +71,8 @@ def this_first_month_day(): now = timezone.now() first_day = timezone.datetime(year=now.year, month=now.month, - day=1) + day=1, + hour=KFET_WAKES_UP_AT) return first_day @@ -78,7 +81,8 @@ def this_monday_morning(): monday = now - timezone.timedelta(days=now.isoweekday()-1) monday_morning = timezone.datetime(year=monday.year, month=monday.month, - day=monday.day) + day=monday.day, + hour=KFET_WAKES_UP_AT) return monday_morning @@ -86,7 +90,8 @@ def this_morning(): now = timezone.now() morning = timezone.datetime(year=now.year, month=now.month, - day=now.day) + day=now.day, + hour=KFET_WAKES_UP_AT) return morning From 0fcb29252b91989c81091337a8f1643b51aa675b Mon Sep 17 00:00:00 2001 From: Evarin Date: Wed, 15 Feb 2017 21:01:54 +0100 Subject: [PATCH 33/34] Frontend tout en JS --- kfet/static/kfet/js/statistic.js | 180 ++++++++++++++++-- kfet/templates/kfet/account_read.html | 14 +- kfet/templates/kfet/account_stat_balance.html | 91 --------- kfet/templates/kfet/account_stat_last.html | 52 ----- kfet/templates/kfet/article_stat_last.html | 82 -------- kfet/templates/kfet/object_stat_resume.html | 35 ---- kfet/views.py | 64 ++++--- 7 files changed, 205 insertions(+), 313 deletions(-) delete mode 100644 kfet/templates/kfet/account_stat_balance.html delete mode 100644 kfet/templates/kfet/account_stat_last.html delete mode 100644 kfet/templates/kfet/article_stat_last.html delete mode 100644 kfet/templates/kfet/object_stat_resume.html diff --git a/kfet/static/kfet/js/statistic.js b/kfet/static/kfet/js/statistic.js index 258f8cc8..6ff13df9 100644 --- a/kfet/static/kfet/js/statistic.js +++ b/kfet/static/kfet/js/statistic.js @@ -1,18 +1,166 @@ -var STAT = {}; +(function($){ + window.StatsGroup = function (url, target) { + // context : array of objects {label, url} + // target : element of the DOM where to put the stats + var self = this; + var element = $(target); + var content = $("
"); + var buttons; -jQuery(document).ready(function() { - // FONCTIONS - // Permet de raffraichir un champ, étant donné : - // thing_url : l'url contenant le contenu - // thing_div : le div où le mettre - // empty_... : le truc à dire si on a un contenu vide - STAT.get_thing = function(thing_url, thing_div, empty_thing_message) { - $.get(thing_url, function(data) { - if(jQuery.trim(data).length==0) { - thing_div.html(empty_thing_message); - } else { - thing_div.html(data); + function dictToArray(dict, start) { + if (start === undefined) start = 0; + // converts the dicts returned by JSONResponse to Arrays + // necessary because for..in does not guarantee the order + var array = new Array(); + for (var k in dict) { + array[k] = dict[k]; + } + array.splice(0, start); + return array; + } + + function handleTimeChart(dict) { + var data = dictToArray(dict, 0); + for (var i = 0; i < data.length; i++) { + var source = data[i]; + data[i] = { x: new Date(source.at), + y: source.balance, + label: source.label } + } + return data; + } + + this.showStats = function() { + buttons.find(".focus").removeClass("focus"); + $(this).addClass("focus"); + + $.getJSON(this.stats_target_url + "?format=json", + self.displayStats); + } + + this.displayStats = function(data) { + // create the chart + var canvas = $(""); + var chart_datasets = []; + var charts = dictToArray(data.charts); + var is_time_chart = data.is_time_chart || false; + for (var i = 0; i < charts.length; i++) { + var chart = charts[i]; + chart_datasets.push( + { + label: chart.label, + borderColor: chart.color, + backgroundColor: chart.color, + fill: false, + lineTension: 0, + data: is_time_chart ? handleTimeChart(chart.values) : dictToArray(chart.values, 1), + }); + } + var chart_options = + { + responsive: true, + tooltips: { + mode: 'index', + intersect: false, + }, + hover: { + mode: 'nearest', + intersect: false, + } } - }); - } -}); + if (is_time_chart) { + chart_options['scales'] = { + xAxes: [{ + type: "time", + display: true, + scaleLabel: { + display: false, + labelString: 'Date' + }, + time: { + tooltipFormat: 'll HH:mm', + //min: new Date("{{ min_date }}"), + //max: new Date("{{ max_date }}"), + displayFormats: { + 'millisecond': 'SSS [ms]', + 'second': 'mm:ss a', + 'minute': 'DD MMM', + 'hour': 'ddd h[h]', + 'day': 'DD MMM', + 'week': 'DD MMM', + 'month': 'MMM', + 'quarter': 'MMM', + 'year': 'YYYY', + } + } + + }], + yAxes: [{ + display: true, + scaleLabel: { + display: false, + labelString: 'value' + } + }] + } + } + + var chart_model = + { + type: 'line', + options: chart_options, + data: { + labels: dictToArray(data.labels, 1), + datasets: chart_datasets, + } + }; + + // display + var prev_chart = content.children(); + content.append(canvas); + + // create the chart + var chart = new Chart(canvas, chart_model); + + // clean + prev_chart.remove(); + } + + // initialize the interface + this.initialize = function (data) { + buttons = $("
", + {class: "btn-group btn-group-justified", + role: "group", + "aria-label": "select-period"}); + var to_click = undefined; + var context = dictToArray(data.stats); + + for (var i = 0; i < context.length; i++) { + var btn_wrapper = $("
", + {class: "btn-group", + role:"group"}); + var btn = $(" -
- {% endfor %} -
-
-
- - diff --git a/kfet/views.py b/kfet/views.py index 586f3d8b..6d8ecb7a 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -7,7 +7,7 @@ from django.views.generic import ListView, DetailView from django.views.generic.list import BaseListView, MultipleObjectTemplateResponseMixin from django.views.generic.detail import BaseDetailView, SingleObjectTemplateResponseMixin from django.views.generic.edit import CreateView, UpdateView, DeleteView, FormView -from django.core.urlresolvers import reverse_lazy +from django.core.urlresolvers import reverse, reverse_lazy from django.contrib import messages from django.contrib.messages.views import SuccessMessageMixin from django.contrib.auth import authenticate, login @@ -1983,6 +1983,14 @@ class JSONResponseMixin(object): return context +class JSONDetailView(JSONResponseMixin, + BaseDetailView): + """ + Returns a DetailView that renders a JSON + """ + def render_to_response(self, context): + return self.render_to_json_response(context) + class HybridDetailView(JSONResponseMixin, SingleObjectTemplateResponseMixin, BaseDetailView): @@ -2013,12 +2021,11 @@ class HybridListView(JSONResponseMixin, return super(HybridListView, self).render_to_response(context) -class ObjectResumeStat(DetailView): +class ObjectResumeStat(JSONDetailView): """ Summarize all the stats of an object - DOES NOT RETURN A JSON RESPONSE + Handles JSONResponse """ - template_name = 'kfet/object_stat_resume.html' context_object_name = '' id_prefix = '' # nombre de vues à résumer @@ -2049,7 +2056,7 @@ class ObjectResumeStat(DetailView): 'btn': "btn_%s_%d_%d" % (self.id_prefix, object_id, i), - 'url': reverse_lazy(self.stat_urls[i], + 'url': reverse(self.stat_urls[i], kwargs=dict( self.get_object_url_kwargs(), **url_kwargs[i] @@ -2072,7 +2079,7 @@ ID_PREFIX_ACC_BALANCE = "balance_acc" # Un résumé de toutes les vues ArticleStatBalance -# NE REND PAS DE JSON +# REND DU JSON class AccountStatBalanceAll(ObjectResumeStat): model = Account context_object_name = 'account' @@ -2105,9 +2112,9 @@ class AccountStatBalanceAll(ObjectResumeStat): return super(AccountStatBalanceAll, self).dispatch(*args, **kwargs) -class AccountStatBalance(HybridDetailView): +class AccountStatBalance(JSONDetailView): """ - Returns a graph (or a JSON Response) of the evolution a the personnal + Returns a JSON containing the evolution a the personnal balance of a trigramme between timezone.now() and `nb_days` ago (specified to the view as an argument) takes into account the Operations and the Transfers @@ -2116,7 +2123,6 @@ class AccountStatBalance(HybridDetailView): model = Account trigramme_url_kwarg = 'trigramme' nb_date_url_kwargs = 'nb_date' - template_name = 'kfet/account_stat_balance.html' context_object_name = 'account' id_prefix = "" @@ -2223,10 +2229,10 @@ class AccountStatBalance(HybridDetailView): nb_days_string = 'anytime' else: nb_days_string = str(int(nb_days)) - context['changes'] = changes - context['chart_id'] = "%s_%s_%s_days" % (self.id_prefix, - self.object.id, - nb_days_string) + context['charts'] = [ { "color": "rgb(255, 99, 132)", + "label": "Balance", + "values": changes } ] + context['is_time_chart'] = True context['min_date'] = changes[len(changes)-1]['at'] context['max_date'] = changes[0]['at'] # TODO: offset @@ -2272,14 +2278,13 @@ class AccountStatLastAll(ObjectResumeStat): return super(AccountStatLastAll, self).dispatch(*args, **kwargs) -class AccountStatLast(HybridDetailView): +class AccountStatLast(JSONDetailView): """ - Returns a graph (or a JSON Response) of the evolution a the personnal + Returns a JSON containing the evolution a the personnal consommation of a trigramme at the diffent dates specified """ model = Account trigramme_url_kwarg = 'trigramme' - template_name = 'kfet/account_stat_last.html' context_object_name = 'account' end_date = timezone.now() id_prefix = "" @@ -2331,10 +2336,9 @@ class AccountStatLast(HybridDetailView): operations = self.sort_operations() for i in operations: nb_ventes[i] = tot_ventes(operations[i]) - context['nb_ventes'] = nb_ventes - # ID unique - context['chart_id'] = "%s_%d" % (self.id_prefix, - self.object.id) + context['charts'] = [ { "color": "rgb(255, 99, 132)", + "label": "NB items achetés", + "values": nb_ventes } ] return context @method_decorator(login_required) @@ -2411,13 +2415,12 @@ class ArticleStatLastAll(ObjectResumeStat): return super(ArticleStatLastAll, self).dispatch(*args, **kwargs) -class ArticleStatLast(HybridDetailView): +class ArticleStatLast(JSONDetailView): """ - Returns a graph (or a JSON Response) of the consommation + Returns a JSON containing the consommation of an article at the diffent dates precised """ model = Article - template_name = 'kfet/article_stat_last.html' context_object_name = 'article' end_date = timezone.now() id_prefix = "" @@ -2478,12 +2481,15 @@ class ArticleStatLast(HybridDetailView): operations[i] .exclude(group__on_acc__trigramme='LIQ') ) - context['nb_ventes'] = nb_ventes - context['nb_accounts'] = nb_accounts - context['nb_liq'] = nb_liq - # ID unique - context['chart_id'] = "%s_%d" % (self.id_prefix, - self.object.id) + context['charts'] = [ { "color": "rgb(255, 99, 132)", + "label": "Toutes consommations", + "values": nb_ventes }, + { "color": "rgb(54, 162, 235)", + "label": "LIQ", + "values": nb_liq }, + { "color": "rgb(255, 205, 86)", + "label": "Comptes K-Fêt", + "values": nb_accounts } ] return context @method_decorator(login_required) From ddbcfe0c69a06855663733b32b1710b8b0d8abba Mon Sep 17 00:00:00 2001 From: Evarin Date: Wed, 15 Feb 2017 22:25:26 +0100 Subject: [PATCH 34/34] =?UTF-8?q?JS=20comment=C3=A9=20et=20plus=20propre?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kfet/static/kfet/js/statistic.js | 79 ++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 24 deletions(-) diff --git a/kfet/static/kfet/js/statistic.js b/kfet/static/kfet/js/statistic.js index 6ff13df9..7ab56f1d 100644 --- a/kfet/static/kfet/js/statistic.js +++ b/kfet/static/kfet/js/statistic.js @@ -1,16 +1,19 @@ (function($){ window.StatsGroup = function (url, target) { - // context : array of objects {label, url} + // a class to properly display statictics + + // url : points to an ObjectResumeStat that lists the options through JSON // target : element of the DOM where to put the stats + var self = this; var element = $(target); var content = $("
"); var buttons; - function dictToArray(dict, start) { - if (start === undefined) start = 0; + function dictToArray (dict, start) { // converts the dicts returned by JSONResponse to Arrays // necessary because for..in does not guarantee the order + if (start === undefined) start = 0; var array = new Array(); for (var k in dict) { array[k] = dict[k]; @@ -19,7 +22,8 @@ return array; } - function handleTimeChart(dict) { + function handleTimeChart (dict) { + // reads the balance data and put it into chartjs formatting var data = dictToArray(dict, 0); for (var i = 0; i < data.length; i++) { var source = data[i]; @@ -30,32 +34,47 @@ return data; } - this.showStats = function() { + function showStats () { + // CALLBACK : called when a button is selected + + // shows the focus on the correct button buttons.find(".focus").removeClass("focus"); $(this).addClass("focus"); - + + // loads data and shows it $.getJSON(this.stats_target_url + "?format=json", - self.displayStats); + displayStats); } - this.displayStats = function(data) { - // create the chart - var canvas = $(""); + function displayStats (data) { + // reads the json data and updates the chart display + var chart_datasets = []; var charts = dictToArray(data.charts); + + // are the points indexed by timestamps? var is_time_chart = data.is_time_chart || false; + + // reads the charts data for (var i = 0; i < charts.length; i++) { var chart = charts[i]; + + // format the data + var chart_data = is_time_chart ? handleTimeChart(chart.values) : dictToArray(chart.values, 1); + chart_datasets.push( { label: chart.label, borderColor: chart.color, backgroundColor: chart.color, - fill: false, + fill: is_time_chart, lineTension: 0, - data: is_time_chart ? handleTimeChart(chart.values) : dictToArray(chart.values, 1), + data: chart_data, + steppedLine: is_time_chart, }); } + + // options for chartjs var chart_options = { responsive: true, @@ -67,7 +86,9 @@ mode: 'nearest', intersect: false, } - } + }; + + // additionnal options for time-indexed charts if (is_time_chart) { chart_options['scales'] = { xAxes: [{ @@ -79,8 +100,6 @@ }, time: { tooltipFormat: 'll HH:mm', - //min: new Date("{{ min_date }}"), - //max: new Date("{{ max_date }}"), displayFormats: { 'millisecond': 'SSS [ms]', 'second': 'mm:ss a', @@ -102,9 +121,10 @@ labelString: 'value' } }] - } + }; } + // global object for the options var chart_model = { type: 'line', @@ -115,8 +135,11 @@ } }; - // display + // saves the previous charts to be destroyed var prev_chart = content.children(); + + // creates a blank canvas element and attach it to the DOM + var canvas = $(""); content.append(canvas); // create the chart @@ -127,15 +150,18 @@ } // initialize the interface - this.initialize = function (data) { + function initialize (data) { + // creates the bar with the buttons buttons = $("
", {class: "btn-group btn-group-justified", role: "group", "aria-label": "select-period"}); - var to_click = undefined; + + var to_click; var context = dictToArray(data.stats); for (var i = 0; i < context.length; i++) { + // creates the button var btn_wrapper = $("
", {class: "btn-group", role:"group"}); @@ -144,23 +170,28 @@ type: "button"}) .text(context[i].label) .prop("stats_target_url", context[i].url) - .on("click", self.showStats); + .on("click", showStats); + // saves the default option to select if (i == data.default_stat || i == 0) to_click = btn; - + + // append the elements to the parent btn_wrapper.append(btn); buttons.append(btn_wrapper); } - + + // appends the contents to the DOM element.append(buttons); element.append(content); - + + // shows the default chart to_click.click(); }; + // constructor (function () { - $.getJSON(url + "?format=json", self.initialize); + $.getJSON(url + "?format=json", initialize); })(); }; })(jQuery);