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 = $("
",
+ {class: "btn btn-primary",
+ type: "button"})
+ .text(context[i].label)
+ .prop("stats_target_url", context[i].url)
+ .on("click", self.showStats);
+
+ if (i == data.default_stat || i == 0)
+ to_click = btn;
+
+ btn_wrapper.append(btn);
+ buttons.append(btn_wrapper);
+ }
+
+ element.append(buttons);
+ element.append(content);
+
+ to_click.click();
+ };
+
+ (function () {
+ $.getJSON(url + "?format=json", self.initialize);
+ })();
+ };
+})(jQuery);
diff --git a/kfet/templates/kfet/account_read.html b/kfet/templates/kfet/account_read.html
index 353c504c..50ab7f20 100644
--- a/kfet/templates/kfet/account_read.html
+++ b/kfet/templates/kfet/account_read.html
@@ -14,14 +14,12 @@
{% endif %}
{% endblock %}
diff --git a/kfet/templates/kfet/account_stat_balance.html b/kfet/templates/kfet/account_stat_balance.html
deleted file mode 100644
index 4d297a21..00000000
--- a/kfet/templates/kfet/account_stat_balance.html
+++ /dev/null
@@ -1,91 +0,0 @@
-
-{% load dictionary_extras %}
-
-
-
- {% comment %}
-
- {% for change in changes %}
-
- {{ change | get_item:'label'}}
- | {{ change | get_item:'at'}}
- | ({{ change | get_item:'amount'}})
- | balance {{ change | get_item:'balance'}}
-
- {% endfor %}
-
- {% endcomment %}
-
-
-
diff --git a/kfet/templates/kfet/account_stat_last.html b/kfet/templates/kfet/account_stat_last.html
deleted file mode 100644
index fe841485..00000000
--- a/kfet/templates/kfet/account_stat_last.html
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
-
-
-
-
diff --git a/kfet/templates/kfet/article_stat_last.html b/kfet/templates/kfet/article_stat_last.html
deleted file mode 100644
index 8b71732f..00000000
--- a/kfet/templates/kfet/article_stat_last.html
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
-
-
-
-
-
diff --git a/kfet/templates/kfet/object_stat_resume.html b/kfet/templates/kfet/object_stat_resume.html
deleted file mode 100644
index 5dba9171..00000000
--- a/kfet/templates/kfet/object_stat_resume.html
+++ /dev/null
@@ -1,35 +0,0 @@
-
-{% load staticfiles %}
-{% load dictionary_extras %}
-
-
- {% for k,stat in stats.items %}
-
- {{ stat | get_item:'label' }}
-
- {% 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)