Functional product stats
This commit is contained in:
1 parent
598e2a8e57
commit
3229d54365
4 files changed
+96
-43
No files matched your search
+4
-3
@@ -6,8 +6,9 @@ urlpatterns = patterns('main.views',
|
|||||||
url(r'^log/$', 'log', name='log'),
|
url(r'^log/$', 'log', name='log'),
|
||||||
url(r'^log/all$', 'log', kwargs={'limit': None}, name='log-all'),
|
url(r'^log/all$', 'log', kwargs={'limit': None}, name='log-all'),
|
||||||
url(r'^stats/$', 'stats', name='stats'),
|
url(r'^stats/$', 'stats', name='stats'),
|
||||||
url(r'^stats/orders$', 'stats_orders', name='stats-orders'),
|
url(r'^stats/orders/$', 'stats_orders', name='stats-orders'),
|
||||||
url(r'^stats/product/(?P<product>[0-9]+)$', 'stats_product', name='stats-product'),
|
url(r'^stats/products/$', 'stats_products', name='stats-products'),
|
||||||
url(r'^products/(?P<product_id>[0-9]+)', 'products', name='json-product'),
|
url(r'^stats/products/(?P<product>[0-9]+)/$', 'stats_products', name='stats-product'),
|
||||||
|
url(r'^products/(?P<product_id>[0-9]+)/$', 'products', name='json-product'),
|
||||||
url(r'^products/$', 'products', name='json-products'),
|
url(r'^products/$', 'products', name='json-products'),
|
||||||
)
|
)
|
||||||
+31
-10
@@ -12,7 +12,7 @@ from django.shortcuts import render_to_response, get_object_or_404
|
|||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.forms.formsets import formset_factory
|
from django.forms.formsets import formset_factory
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.db.models import Count
|
from django.db.models import Count, Sum
|
||||||
|
|
||||||
from models import *
|
from models import *
|
||||||
|
|
||||||
@@ -143,10 +143,7 @@ def serialize_product(product):
|
|||||||
f_product = {}
|
f_product = {}
|
||||||
for attr in Product._meta.get_all_field_names():
|
for attr in Product._meta.get_all_field_names():
|
||||||
if hasattr(product, attr) and product.__getattribute__(attr):
|
if hasattr(product, attr) and product.__getattribute__(attr):
|
||||||
#print type(product.__getattribute__(attr))
|
|
||||||
if type(product.__getattribute__(attr)) is datetime:
|
if type(product.__getattribute__(attr)) is datetime:
|
||||||
# TODO parse datetime
|
|
||||||
date = product.__getattribute__(attr)
|
|
||||||
f_product[attr] = str(product.__getattribute__(attr))
|
f_product[attr] = str(product.__getattribute__(attr))
|
||||||
else:
|
else:
|
||||||
f_product[attr] = product.__getattribute__(attr)
|
f_product[attr] = product.__getattribute__(attr)
|
||||||
@@ -167,21 +164,45 @@ def products(request, product_id=None):
|
|||||||
|
|
||||||
return HttpResponse(json.dumps(f_products), content_type='application/javascript; charset=utf8')
|
return HttpResponse(json.dumps(f_products), content_type='application/javascript; charset=utf8')
|
||||||
|
|
||||||
def stats_product(request, product):
|
def stats_product(product):
|
||||||
sales = OrderLine.objects.filter(product=product)
|
sales = OrderLine.objects.filter(product=product)
|
||||||
total = float(sales.count())
|
# reverse lookup via order, customer
|
||||||
per_user = sales.values('order__customer__first_name','order__customer__last_name').annotate(num=Count('order__customer')).order_by('num')
|
per_user = sales.values('order__customer__first_name','order__customer__last_name').annotate(num=Sum('amount')).order_by('num').reverse()
|
||||||
f_per_user = []
|
f_per_user = []
|
||||||
for row in per_user:
|
for row in per_user:
|
||||||
who = row['order__customer__first_name'] + " " + row['order__customer__last_name'][0]
|
who = row['order__customer__first_name'] + " " + row['order__customer__last_name'][0]
|
||||||
num = row['num']
|
num = row['num']
|
||||||
f_per_user.append([who, num])
|
f_per_user.append([who, num])
|
||||||
return HttpResponse(json.dumps(f_per_user), content_type='application/javascript; charset=utf8')
|
response = {
|
||||||
|
'product' : serialize_product(Product.objects.get(pk=product)) if type(product) is unicode else serialize_product(product),
|
||||||
|
'counts' : f_per_user,
|
||||||
|
'total_counts' : sum([row['num'] for row in per_user]),
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
|
||||||
|
def stats_products(request, product=None):
|
||||||
|
if product:
|
||||||
|
#single
|
||||||
|
f_products = [stats_product(product)]
|
||||||
|
sales = OrderLine.objects.filter(product=product)
|
||||||
|
else:
|
||||||
|
#all
|
||||||
|
sales = OrderLine.objects.filter(product__active=True)
|
||||||
|
f_products = [stats_product(p) for p in Product.objects.filter(active=True)]
|
||||||
|
|
||||||
|
totals = float(sum([sale.amount for sale in sales]))
|
||||||
|
response = {
|
||||||
|
'request' : 'all' if not product else product,
|
||||||
|
'response' : {
|
||||||
|
'products' : f_products,
|
||||||
|
'total_count' : totals,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return HttpResponse(json.dumps(response), content_type='application/javascript; charset=utf8')
|
||||||
|
|
||||||
def stats_orders(request):
|
def stats_orders(request):
|
||||||
|
|
||||||
total = float(Order.objects.count())
|
total = float(Order.objects.count())
|
||||||
per_user = Order.objects.values('customer__first_name','customer__last_name').annotate(num=Count('customer')).order_by('num')
|
per_user = Order.objects.values('customer__first_name','customer__last_name').annotate(num=Count('customer')).order_by('num').reverse()
|
||||||
f_per_user = []
|
f_per_user = []
|
||||||
for row in per_user:
|
for row in per_user:
|
||||||
who = row['customer__first_name'] + " " + row['customer__last_name'][0]
|
who = row['customer__first_name'] + " " + row['customer__last_name'][0]
|
||||||
|
|||||||
+56
-27
@@ -1,40 +1,25 @@
|
|||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
var charts = [];
|
var charts = [];
|
||||||
var products_url = '/products';
|
var products_url = '/stats/products/';
|
||||||
|
var order_url = '/stats/orders/';
|
||||||
|
|
||||||
|
/* orders */
|
||||||
|
$.getJSON(order_url, function(data) {
|
||||||
|
var render_to = 'order_chart';
|
||||||
|
|
||||||
/* drink beer and... */
|
|
||||||
$.getJSON(products_url, function(data) {
|
|
||||||
var graph_mappings = [
|
|
||||||
{
|
|
||||||
'url' : '/stats/orders',
|
|
||||||
'render_to' : 'order_chart'
|
|
||||||
}];
|
|
||||||
var products = data;
|
|
||||||
for(i in products) {
|
|
||||||
var mapping = {
|
|
||||||
'url' : '/stats/product/' + products[i].id,
|
|
||||||
'info_url' : '/products/' + products[i].id,
|
|
||||||
'render_to' : 'product_chart' + products[i].id
|
|
||||||
};
|
|
||||||
graph_mappings.push(mapping);
|
|
||||||
}
|
|
||||||
for(i in graph_mappings) {
|
|
||||||
// define the options
|
// define the options
|
||||||
var options = {
|
var options = {
|
||||||
credits: {
|
credits: {
|
||||||
enabled: false
|
enabled: false
|
||||||
},
|
},
|
||||||
chart: {
|
chart: {
|
||||||
/* TODO this is not updated right.
|
renderTo: render_to,
|
||||||
* ie. how to get ajax-callback to update the right options-object?
|
|
||||||
* */
|
|
||||||
renderTo: graph_mappings[i].render_to,
|
|
||||||
plotBackgroundColor: null,
|
plotBackgroundColor: null,
|
||||||
plotBorderWidth: null,
|
plotBorderWidth: null,
|
||||||
plotShadow: false
|
plotShadow: false
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
text: 'Antall ordre per bruker'
|
text: 'Fordeling av ordre på person'
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
formatter: function() {
|
formatter: function() {
|
||||||
@@ -58,14 +43,58 @@ $(document).ready(function() {
|
|||||||
series: [{
|
series: [{
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
name: 'Orders',
|
name: 'Orders',
|
||||||
data: []
|
data: data
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
$.getJSON(graph_mappings[i].url, function(data) {
|
|
||||||
options.series[0].data = data,
|
|
||||||
charts.push(new Highcharts.Chart(options));
|
charts.push(new Highcharts.Chart(options));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* products */
|
||||||
|
$.getJSON(products_url, function(data) {
|
||||||
|
var products = data.response.products;
|
||||||
|
for(i in products) {
|
||||||
|
var render_to = 'product_chart' + products[i].product.id;
|
||||||
|
var series_data = products[i].counts;
|
||||||
|
// define the options
|
||||||
|
var options = {
|
||||||
|
credits: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
chart: {
|
||||||
|
renderTo: render_to,
|
||||||
|
plotBackgroundColor: null,
|
||||||
|
plotBorderWidth: null,
|
||||||
|
plotShadow: false
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: products[i].product.name
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
formatter: function() {
|
||||||
|
return '<b>'+ this.point.name +'</b>: '+ Highcharts.numberFormat(this.percentage, 1) +' %';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
pie: {
|
||||||
|
allowPointSelect: true,
|
||||||
|
cursor: 'pointer',
|
||||||
|
dataLabels: {
|
||||||
|
enabled: true,
|
||||||
|
color: '#000000',
|
||||||
|
connectorColor: '#000000',
|
||||||
|
formatter: function() {
|
||||||
|
return '<b>'+ this.point.name +'</b>: ' + this.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
type: 'pie',
|
||||||
|
name: 'Orders',
|
||||||
|
data: series_data
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
charts.push(new Highcharts.Chart(options));
|
||||||
}
|
}
|
||||||
console.log(charts);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -13,16 +13,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section id="product" class="row-fluid">
|
||||||
|
<h2>Produkter</h2>
|
||||||
{% for product in products %}
|
{% for product in products %}
|
||||||
<section id="product_{{ product.id }}" class="row-fluid">
|
<section id="product_{{ product.id }}">
|
||||||
<div class="span12">
|
<div class="span6">
|
||||||
<h2>{{ product }}</h2>
|
|
||||||
<div id="product_chart{{ product.id }}"></div>
|
<div id="product_chart{{ product.id }}"></div>
|
||||||
<!--<div id="container" style="width: 800px; height: 400px; margin: 0 auto;"></div> -->
|
<!--<div id="container" style="width: 800px; height: 400px; margin: 0 auto;"></div> -->
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</section>
|
</section>
|
||||||
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block tailinc %}
|
{% block tailinc %}
|
||||||
<script src="{{ STATIC_URL }}js/bootstrap-typeahead.js"></script>
|
<script src="{{ STATIC_URL }}js/bootstrap-typeahead.js"></script>
|
||||||
|
|||||||
Reference in new issue
Block a user