Adds initial profile page
This commit is contained in:
1 parent
fc65e15d98
commit
f8a94b7bee
10 files changed
+195
-22
No files matched your search
+9
-6
@@ -50,19 +50,22 @@ class Product(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
class Order(models.Model):
|
class Order(models.Model):
|
||||||
customer = models.ForeignKey(User, null=True, blank=True)
|
customer = models.ForeignKey(User, null=True, blank=True, related_name='orders')
|
||||||
order_sum = models.FloatField(db_column='sum')
|
order_sum = models.FloatField(db_column='sum')
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
def is_external(self):
|
def is_external(self):
|
||||||
return self.customer is None
|
return self.customer is None
|
||||||
|
|
||||||
|
def reciept(self):
|
||||||
|
return u"{0}".format(u", ".join([str(ol) for ol in self.orderlines.all()]))
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"{0}: {1} kr".format(self.customer or u"Ekstern", self.order_sum)
|
return u"{0}: {1} kr".format(self.customer or u"Ekstern", self.order_sum)
|
||||||
|
|
||||||
|
|
||||||
class OrderLine(models.Model):
|
class OrderLine(models.Model):
|
||||||
order = models.ForeignKey('main.Order')
|
order = models.ForeignKey('main.Order', related_name='orderlines')
|
||||||
product = models.ForeignKey('main.Product', related_name='orderlines')
|
product = models.ForeignKey('main.Product', related_name='orderlines')
|
||||||
amount = models.IntegerField()
|
amount = models.IntegerField()
|
||||||
unit_price = models.FloatField(verbose_name=_('Enhetspris'))
|
unit_price = models.FloatField(verbose_name=_('Enhetspris'))
|
||||||
@@ -80,7 +83,7 @@ class OrderLine(models.Model):
|
|||||||
|
|
||||||
class Transaction(models.Model):
|
class Transaction(models.Model):
|
||||||
""" Money """
|
""" Money """
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User, related_name='transactions')
|
||||||
amount = models.FloatField()
|
amount = models.FloatField()
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
@@ -90,7 +93,7 @@ class Transaction(models.Model):
|
|||||||
|
|
||||||
class InventoryTransaction(models.Model):
|
class InventoryTransaction(models.Model):
|
||||||
""" Goods """
|
""" Goods """
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User, related_name='inventory_transactions')
|
||||||
product = models.ForeignKey('main.Product', related_name='transactions', verbose_name=_('Produkt'))
|
product = models.ForeignKey('main.Product', related_name='transactions', verbose_name=_('Produkt'))
|
||||||
amount = models.FloatField(verbose_name=_('Antall'))
|
amount = models.FloatField(verbose_name=_('Antall'))
|
||||||
unit_price = models.FloatField(verbose_name=_('Enhetspris'))
|
unit_price = models.FloatField(verbose_name=_('Enhetspris'))
|
||||||
@@ -117,9 +120,9 @@ class UserProfile(models.Model):
|
|||||||
image = models.URLField(blank=True)
|
image = models.URLField(blank=True)
|
||||||
|
|
||||||
def last_purchase(self):
|
def last_purchase(self):
|
||||||
if len(self.user.order_set.all()) == 0:
|
if len(self.user.orders.all()) == 0:
|
||||||
return None
|
return None
|
||||||
return self.user.order_set.order_by('created').reverse()[0]
|
return self.user.orders.order_by('created').reverse()[0]
|
||||||
|
|
||||||
def last_purchase_date(self):
|
def last_purchase_date(self):
|
||||||
last = self.last_purchase()
|
last = self.last_purchase()
|
||||||
|
|||||||
@@ -12,9 +12,11 @@ urlpatterns = patterns('main.views',
|
|||||||
url(r'^stats/orders/products_realtime$', 'stats_products_realtime', name='stats-products-realtime'),
|
url(r'^stats/orders/products_realtime$', 'stats_products_realtime', name='stats-products-realtime'),
|
||||||
url(r'^stats/products/$', 'stats_products', name='stats-products'),
|
url(r'^stats/products/$', 'stats_products', name='stats-products'),
|
||||||
url(r'^stats/products/(?P<product>[0-9]+)/$', 'stats_products', name='stats-product'),
|
url(r'^stats/products/(?P<product>[0-9]+)/$', 'stats_products', name='stats-product'),
|
||||||
|
url(r'^stats/products/by_user/(?P<user_id>[0-9]+)/$', 'stats_products_per_user', name='stats-products-per-user'),
|
||||||
url(r'^products/(?P<product_id>[0-9]+)/$', 'products_json', name='json-product'),
|
url(r'^products/(?P<product_id>[0-9]+)/$', 'products_json', name='json-product'),
|
||||||
url(r'^products/$', 'products_json', name='json-products'),
|
url(r'^products/$', 'products_json', name='json-products'),
|
||||||
url(r'^user/create/$', 'create_user', name='create-user'),
|
url(r'^user/create/$', 'create_user', name='create-user'),
|
||||||
|
url(r'^profile/$', 'profile', name='profile'),
|
||||||
url(r'^inventory/$', 'inventory', name='inventory'),
|
url(r'^inventory/$', 'inventory', name='inventory'),
|
||||||
url(r'^inventory/add/$', 'inventory_add', name='inventory-add'),
|
url(r'^inventory/add/$', 'inventory_add', name='inventory-add'),
|
||||||
url(r'^report$', 'report', name='report'),
|
url(r'^report$', 'report', name='report'),
|
||||||
|
|||||||
+54
-2
@@ -4,9 +4,11 @@ from itertools import groupby
|
|||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from django.db import connection
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.forms import AuthenticationForm
|
|
||||||
from django.contrib.auth import login, logout as auth_logout
|
from django.contrib.auth import login, logout as auth_logout
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.contrib.auth.forms import AuthenticationForm
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.db.models import Count, Sum, Min
|
from django.db.models import Count, Sum, Min
|
||||||
@@ -14,7 +16,6 @@ from django.forms.formsets import formset_factory
|
|||||||
from django.http import HttpResponse, HttpResponseRedirect
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
from django.shortcuts import render_to_response, render, get_object_or_404, redirect
|
from django.shortcuts import render_to_response, render, get_object_or_404, redirect
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
|
|
||||||
from forms import *
|
from forms import *
|
||||||
from models import *
|
from models import *
|
||||||
import utils
|
import utils
|
||||||
@@ -488,3 +489,54 @@ def report(request):
|
|||||||
saldo_diff = saldo_end - saldo_start
|
saldo_diff = saldo_end - saldo_start
|
||||||
|
|
||||||
return render(request, 'report.html', locals())
|
return render(request, 'report.html', locals())
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def profile(request):
|
||||||
|
transactions = Transaction.objects.filter(user=request.user.pk)
|
||||||
|
transaction_totals = {
|
||||||
|
'sum': sum([t.amount for t in transactions])
|
||||||
|
}
|
||||||
|
orders = Order.objects.filter(customer=request.user.pk)
|
||||||
|
orders_totals = {
|
||||||
|
'sum': sum([o.order_sum for o in orders])
|
||||||
|
}
|
||||||
|
|
||||||
|
#order_lines = OrderLine.objects.filter(order__customer__pk=1).order_by("order__created")
|
||||||
|
order_report = _orders_monthly(filter_by={'customer': request.user.pk})
|
||||||
|
top_months = order_report.order_by('-sum')[:5]
|
||||||
|
return render(request, 'profile.html', locals())
|
||||||
|
|
||||||
|
|
||||||
|
def stats_products_per_user(request, user_id=None):
|
||||||
|
if not user_id:
|
||||||
|
return HttpResponse(
|
||||||
|
json.dumps({'error': 'Missing param user_id'}),
|
||||||
|
content_type='application/javascript; charset=utf8')
|
||||||
|
|
||||||
|
order_lines = OrderLine.objects.filter(order__customer__pk=user_id).order_by("order__created")
|
||||||
|
products = {}
|
||||||
|
for order_line in order_lines:
|
||||||
|
order_time_in_milliseconds = int(time.mktime(order_line.order.created.timetuple()) * 1000)
|
||||||
|
if order_line.product not in products:
|
||||||
|
products[order_line.product] = [[order_time_in_milliseconds, order_line.amount]]
|
||||||
|
else:
|
||||||
|
prev_entry = products[order_line.product][-1]
|
||||||
|
products[order_line.product].append([order_time_in_milliseconds, prev_entry[1] + order_line.amount])
|
||||||
|
|
||||||
|
serialized_products = []
|
||||||
|
for product, value in products.iteritems():
|
||||||
|
serialized_products.append({
|
||||||
|
'name': product.name,
|
||||||
|
'data': value
|
||||||
|
})
|
||||||
|
return HttpResponse(json.dumps(serialized_products), content_type='application/javascript; charset=utf8')
|
||||||
|
|
||||||
|
|
||||||
|
def _orders_monthly(filter_by={}, order_by='month'):
|
||||||
|
|
||||||
|
truncate_date = connection.ops.date_trunc_sql('month', 'created')
|
||||||
|
qs = Order.objects.filter(**filter_by).extra({'month': truncate_date})
|
||||||
|
order_report = qs.values('month').annotate(sum=Sum('order_sum'), num=Count('pk')).order_by(order_by)
|
||||||
|
|
||||||
|
return order_report
|
||||||
+43
-9
@@ -105,6 +105,13 @@ $(document).ready(function() {
|
|||||||
update_total(this);
|
update_total(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* Set Global Highcharts options */
|
||||||
|
|
||||||
|
Highcharts.setOptions({
|
||||||
|
credits: {
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* View: Register
|
* View: Register
|
||||||
@@ -163,9 +170,6 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
// define the options
|
// define the options
|
||||||
var options = {
|
var options = {
|
||||||
credits: {
|
|
||||||
enabled: false
|
|
||||||
},
|
|
||||||
chart: {
|
chart: {
|
||||||
renderTo: render_to,
|
renderTo: render_to,
|
||||||
plotBackgroundColor: null,
|
plotBackgroundColor: null,
|
||||||
@@ -211,9 +215,6 @@ $(document).ready(function() {
|
|||||||
var series_data = products[i].counts;
|
var series_data = products[i].counts;
|
||||||
// define the options
|
// define the options
|
||||||
var options = {
|
var options = {
|
||||||
credits: {
|
|
||||||
enabled: false
|
|
||||||
},
|
|
||||||
chart: {
|
chart: {
|
||||||
renderTo: render_to,
|
renderTo: render_to,
|
||||||
plotBackgroundColor: null,
|
plotBackgroundColor: null,
|
||||||
@@ -257,9 +258,6 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
// define the options
|
// define the options
|
||||||
var options = {
|
var options = {
|
||||||
credits: {
|
|
||||||
enabled: false
|
|
||||||
},
|
|
||||||
chart: {
|
chart: {
|
||||||
renderTo: render_to,
|
renderTo: render_to,
|
||||||
type: 'column'
|
type: 'column'
|
||||||
@@ -443,4 +441,40 @@ $(document).ready(function() {
|
|||||||
}).on('changeDate', function(e) {
|
}).on('changeDate', function(e) {
|
||||||
start_field.datepicker('setEndDate', e.date);
|
start_field.datepicker('setEndDate', e.date);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* View: Profile
|
||||||
|
*/
|
||||||
|
if( $('#user-profile').length ) {
|
||||||
|
var products_by_user_url = '/stats/products/by_user/';
|
||||||
|
var user_id = $('#user-profile').attr('data-user-id');
|
||||||
|
|
||||||
|
$.getJSON(products_by_user_url + user_id, function(data) {
|
||||||
|
if(data.hasOwnProperty('error')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$(".profile-stats-orderline").highcharts({
|
||||||
|
title: {
|
||||||
|
text: false
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: "datetime"
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
title: {
|
||||||
|
text: "Kjøp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
plotOptions: {
|
||||||
|
series: {
|
||||||
|
marker: {
|
||||||
|
radius: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: data
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
@@ -156,6 +156,16 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#user-profile {
|
||||||
|
.profile-name {
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 50px;
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
.profile-image {
|
||||||
|
border-radius: 50% 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
#footer .credits {
|
#footer .credits {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 2em;
|
margin: 2em;
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1 +1 @@
|
|||||||
function enable_all_customers(){$("li.customer").each(function(){$(this).removeClass("marked"),$(this).show()})}function filter_customers(t){setTimeout(function(){$("li.customer").each(function(){var e=new RegExp(t,"i"),r=$(this).children("span.name").text();if(e.test(r)){$(this).show();var a=r.toLowerCase()==t.toLowerCase(),o=1==$("li.customer:visible").length;console.log(a,o),a?$(this).addClass("marked"):$(this).removeClass("marked")}else $(this).hide(),$(this).removeClass("marked")})},50)}function enable_all_products(){$("li.product").each(function(){$(this).removeClass("marked"),$(this).show()})}function reset_qtys(){$(".qty").each(function(){$(this).html("0")}),$("input[name$=amount]").each(function(){$(this).val("0")})}function update_total(){var t=0;$("li.product").each(function(){var e=Number($(this).find("[name$=amount]").val()),r=".sale_price_int";"Ekstern"===$("#id_customer_typeahead").val()&&(r=".sale_price_ext");var a=Number($(this).find(r).text());t+=e*a}),0===t&&(t=""),$("span.total_text").html(t)}$(document).ready(function(){function t(t){var e=s;for(var r in t.products)if(null===e.get(r)){e.addSeries({data:[],id:r,name:r});var a=e.get(r);_.each(t.products[r],function(t){a.addPoint({id:t[0],x:t[0],y:t[1]})})}else{var a=e.get(r);_.each(t.products[r],function(t){null===e.get(t[0])&&a.addPoint({id:t[0],x:t[0],y:t[1]})})}}function e(){$.ajax({url:n,dataType:"json",success:function(r){t(r),setTimeout(function(){e()},15e3)},cache:!1})}if($("a[data-dismiss=alert]").click(function(){$(this).parent().parent().parent().slideUp()}),setTimeout(function(){$("a[data-dismiss=alert]").parent().parent().parent().slideUp()},5e3),$("h2").tooltip({placement:"right"}),$("img.customer").tooltip(),$("a.product").tooltip(),$("#footer .credits .love").tooltip(),$("#id_customer_typeahead").keyup(function(t){filter_customers(t.target.value)}),$("li.customer").click(function(){enable_all_customers(),$(this).addClass("marked");var t=$(this).children("span.name").text();$("#id_customer_typeahead").val(t);var e=$(this).children("span.id").text();$("#id_customer option, #id_user option").removeAttr("selected"),""===e?$("#id_customer option:first-child, #id_user option:first-child").attr("selected","selected"):$("#id_customer option[value="+e+"], #id_user option[value="+e+"]").attr("selected","selected"),update_total(this)}),$("#register li.product").click(function(){$(this).addClass("marked");var t=$(this).children("input[name$=amount]"),e=$(this).children(".qty"),r=Number(t.val())+1;t.val(r),e.html(r),update_total(this)}),$("#register button[type=reset]").click(function(){$("#id_customer option").removeAttr("selected"),$("#id_customer_typeahead").val(""),$("span.total_text").html(""),enable_all_customers(),enable_all_products(),reset_qtys()}),$(".toggle-infrequent-users").on("click",function(t){t.preventDefault(),$("li.customer.infrequent").toggleClass("hidden"),$(".users-description .infrequent-users").toggleClass("hidden"),$(this).text("Vis alle"===$(this).text()?"Skjul gamliser":"Vis alle")}),$("#stats").length>0){var r=[],a="/stats/products/",o="/stats/orders/",i="/stats/orders/hourly",n="/stats/orders/products_realtime";$.getJSON(o,function(t){var e="order_chart",a={credits:{enabled:!1},chart:{renderTo:e,plotBackgroundColor:null,plotBorderWidth:null,plotShadow:!1},title:{text:"Fordeling av ordre på person"},tooltip:{formatter:function(){return"<b>"+this.point.name+"</b>: "+Highcharts.numberFormat(this.percentage,1)+" %"}},plotOptions:{pie:{allowPointSelect:!0,cursor:"pointer",dataLabels:{enabled:!0,color:"#000000",connectorColor:"#000000",formatter:function(){return"<b>"+this.point.name+"</b>: "+this.y}}}},series:[{type:"pie",name:"Orders",data:t}]};r.push(new Highcharts.Chart(a))}),$.getJSON(a,function(t){var e=t.response.products;for(var a in e){var o="product_chart"+e[a].product.id,i=e[a].counts,n={credits:{enabled:!1},chart:{renderTo:o,plotBackgroundColor:null,plotBorderWidth:null,plotShadow:!1},title:{text:e[a].product.name},tooltip:{formatter:function(){return"<b>"+this.point.name+"</b>: "+Highcharts.numberFormat(this.percentage,1)+" %"}},plotOptions:{pie:{allowPointSelect:!0,cursor:"pointer",dataLabels:{enabled:!0,color:"#000000",connectorColor:"#000000",formatter:function(){return"<b>"+this.point.name+"</b>: "+this.y}}}},series:[{type:"pie",name:"Orders",data:i}]};r.push(new Highcharts.Chart(n))}}),$.getJSON(i,function(t){var e="order_hourly_chart",a={credits:{enabled:!1},chart:{renderTo:e,type:"column"},title:{text:"Ordre - time for time"},tooltip:{formatter:function(){return this.y+" stk"}},yAxis:{title:{text:"Ordre"}},xAxis:{title:{text:"Tid (h)"},labels:{formatter:function(){return this.value+":00"}}},plotOptions:{column:{minPointLength:3},series:{groupPadding:0,pointPadding:.05}},series:[{name:"Ordre",data:t.hourly}]};r.push(new Highcharts.Chart(a))});var s=new Highcharts.Chart({chart:{renderTo:"products_realtime_chart"},title:{text:"Produkter solgt over tid"},xAxis:{type:"datetime"},yAxis:{title:{textLine truncated
|
function enable_all_customers(){$("li.customer").each(function(){$(this).removeClass("marked"),$(this).show()})}function filter_customers(t){setTimeout(function(){$("li.customer").each(function(){var e=new RegExp(t,"i"),r=$(this).children("span.name").text();if(e.test(r)){$(this).show();var a=r.toLowerCase()==t.toLowerCase(),i=1==$("li.customer:visible").length;console.log(a,i),a?$(this).addClass("marked"):$(this).removeClass("marked")}else $(this).hide(),$(this).removeClass("marked")})},50)}function enable_all_products(){$("li.product").each(function(){$(this).removeClass("marked"),$(this).show()})}function reset_qtys(){$(".qty").each(function(){$(this).html("0")}),$("input[name$=amount]").each(function(){$(this).val("0")})}function update_total(){var t=0;$("li.product").each(function(){var e=Number($(this).find("[name$=amount]").val()),r=".sale_price_int";"Ekstern"===$("#id_customer_typeahead").val()&&(r=".sale_price_ext");var a=Number($(this).find(r).text());t+=e*a}),0===t&&(t=""),$("span.total_text").html(t)}$(document).ready(function(){function t(t){var e=n;for(var r in t.products)if(null===e.get(r)){e.addSeries({data:[],id:r,name:r});var a=e.get(r);_.each(t.products[r],function(t){a.addPoint({id:t[0],x:t[0],y:t[1]})})}else{var a=e.get(r);_.each(t.products[r],function(t){null===e.get(t[0])&&a.addPoint({id:t[0],x:t[0],y:t[1]})})}}function e(){$.ajax({url:s,dataType:"json",success:function(r){t(r),setTimeout(function(){e()},15e3)},cache:!1})}if($("a[data-dismiss=alert]").click(function(){$(this).parent().parent().parent().slideUp()}),setTimeout(function(){$("a[data-dismiss=alert]").parent().parent().parent().slideUp()},5e3),$("h2").tooltip({placement:"right"}),$("img.customer").tooltip(),$("a.product").tooltip(),$("#footer .credits .love").tooltip(),$("#id_customer_typeahead").keyup(function(t){filter_customers(t.target.value)}),$("li.customer").click(function(){enable_all_customers(),$(this).addClass("marked");var t=$(this).children("span.name").text();$("#id_customer_typeahead").val(t);var e=$(this).children("span.id").text();$("#id_customer option, #id_user option").removeAttr("selected"),""===e?$("#id_customer option:first-child, #id_user option:first-child").attr("selected","selected"):$("#id_customer option[value="+e+"], #id_user option[value="+e+"]").attr("selected","selected"),update_total(this)}),Highcharts.setOptions({credits:{enabled:!1}}),$("#register li.product").click(function(){$(this).addClass("marked");var t=$(this).children("input[name$=amount]"),e=$(this).children(".qty"),r=Number(t.val())+1;t.val(r),e.html(r),update_total(this)}),$("#register button[type=reset]").click(function(){$("#id_customer option").removeAttr("selected"),$("#id_customer_typeahead").val(""),$("span.total_text").html(""),enable_all_customers(),enable_all_products(),reset_qtys()}),$(".toggle-infrequent-users").on("click",function(t){t.preventDefault(),$("li.customer.infrequent").toggleClass("hidden"),$(".users-description .infrequent-users").toggleClass("hidden"),$(this).text("Vis alle"===$(this).text()?"Skjul gamliser":"Vis alle")}),$("#stats").length>0){var r=[],a="/stats/products/",i="/stats/orders/",o="/stats/orders/hourly",s="/stats/orders/products_realtime";$.getJSON(i,function(t){var e="order_chart",a={chart:{renderTo:e,plotBackgroundColor:null,plotBorderWidth:null,plotShadow:!1},title:{text:"Fordeling av ordre på person"},tooltip:{formatter:function(){return"<b>"+this.point.name+"</b>: "+Highcharts.numberFormat(this.percentage,1)+" %"}},plotOptions:{pie:{allowPointSelect:!0,cursor:"pointer",dataLabels:{enabled:!0,color:"#000000",connectorColor:"#000000",formatter:function(){return"<b>"+this.point.name+"</b>: "+this.y}}}},series:[{type:"pie",name:"Orders",data:t}]};r.push(new Highcharts.Chart(a))}),$.getJSON(a,function(t){var e=t.response.products;for(var a in e){var i="product_chart"+e[a].product.id,o=e[a].counts,s={chart:{renderTo:i,plotBackgroundColor:null,plotBorderWidth:null,plotShadow:!1},title:{text:e[a].product.name},tooltip:{formatter:function(){return"<b>"+this.point.name+"</b>: "+Highcharts.numberFormat(this.percentage,1)+" %"}},plotOptions:{pie:{allowPointSelect:!0,cursor:"pointer",dataLabels:{enabled:!0,color:"#000000",connectorColor:"#000000",formatter:function(){return"<b>"+this.point.name+"</b>: "+this.y}}}},series:[{type:"pie",name:"Orders",data:o}]};r.push(new Highcharts.Chart(s))}}),$.getJSON(o,function(t){var e="order_hourly_chart",a={chart:{renderTo:e,type:"column"},title:{text:"Ordre - time for time"},tooltip:{formatter:function(){return this.y+" stk"}},yAxis:{title:{text:"Ordre"}},xAxis:{title:{text:"Tid (h)"},labels:{formatter:function(){return this.value+":00"}}},plotOptions:{column:{minPointLength:3},series:{groupPadding:0,pointPadding:.05}},series:[{name:"Ordre",data:t.hourly}]};r.push(new Highcharts.Chart(a))});var n=new Highcharts.Chart({chart:{renderTo:"products_realtime_chart"},title:{text:"Produkter solgt over tid"},xAxis:{type:"datetime"},yAxis:{title:{text:"Antall solgt"}}Line truncated
|
||||||
Vendored
+1
-1
@@ -1 +1 @@
|
|||||||
/*! normalize.css v3.0.1 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0}mark{background:#ff0;color:#000}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}hr{box-sizing:content-box;height:0}pre{overflow:auto}samp{font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{*{text-shadow:none!important;color:#000!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href)")"}abbr[title]:after{content:" (" attr(title)")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url('/static/dist/fonts/glyphicons-halflings-regular.eot');src:url('/static/dist/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('/static/dist/fonts/glyphicons-halflings-regular.woff') format('woff'),url('/static/dist/fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('/static/dist/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{Line truncated
|
/*! normalize.css v3.0.1 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0}mark{background:#ff0;color:#000}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}hr{box-sizing:content-box;height:0}pre{overflow:auto}samp{font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{*{text-shadow:none!important;color:#000!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href)")"}abbr[title]:after{content:" (" attr(title)")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url('/static/dist/fonts/glyphicons-halflings-regular.eot');src:url('/static/dist/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('/static/dist/fonts/glyphicons-halflings-regular.woff') format('woff'),url('/static/dist/fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('/static/dist/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{Line truncated
|
||||||
@@ -40,6 +40,7 @@
|
|||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><img src="{{ user.get_profile.profile_image_url }}" /><span class="name">{{ user.first_name }}</span> <b class="caret"></b></a>
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><img src="{{ user.get_profile.profile_image_url }}" /><span class="name">{{ user.first_name }}</span> <b class="caret"></b></a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
|
{% if request.user.is_authenticated %}<li class="{% block active_profile %}{% endblock %}"><a href="{% url 'profile' %}"><i class="glyphicon glyphicon-user"></i> Profil</a></li>{% endif %}
|
||||||
<li class="{% block active_create_user %}{% endblock %}"><a href="{% url 'create-user' %}"><i class="glyphicon glyphicon-plus"></i> Ny bruker</a></li>
|
<li class="{% block active_create_user %}{% endblock %}"><a href="{% url 'create-user' %}"><i class="glyphicon glyphicon-plus"></i> Ny bruker</a></li>
|
||||||
{% if request.user.is_superuser %}<li><a href="/admin"><i class="glyphicon glyphicon-cog"></i> Administrasjon</a></li>{% endif %}
|
{% if request.user.is_superuser %}<li><a href="/admin"><i class="glyphicon glyphicon-cog"></i> Administrasjon</a></li>{% endif %}
|
||||||
{% if request.user.is_superuser %}<li class="{% block active_inventory %}{% endblock %}"><a href="{% url 'inventory' %}"><i class="glyphicon glyphicon-briefcase"></i> Varebeholdning</a></li>{% endif %}
|
{% if request.user.is_superuser %}<li class="{% block active_inventory %}{% endblock %}"><a href="{% url 'inventory' %}"><i class="glyphicon glyphicon-briefcase"></i> Varebeholdning</a></li>{% endif %}
|
||||||
|
|||||||
@@ -32,13 +32,13 @@
|
|||||||
<td>{{ product.wholesale_unit_price|default:"-" }}</td>
|
<td>{{ product.wholesale_unit_price|default:"-" }}</td>
|
||||||
<td>{{ product.wholesale_value|default:"-" }}</td>
|
<td>{{ product.wholesale_value|default:"-" }}</td>
|
||||||
<td class="product-active">{% if product.active %}<i class="glyphicon glyphicon-ok"></i>{% endif %}</td>
|
<td class="product-active">{% if product.active %}<i class="glyphicon glyphicon-ok"></i>{% endif %}</td>
|
||||||
<td>{{ product.updated }}</td>
|
<td>{{ product.updated|date:"c" }}</td>
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td>Sum</td>
|
||||||
<td>{{ num_products }} totalt</td>
|
<td>{{ num_products }}</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>{{ wholesale_value }}</td>
|
<td>{{ wholesale_value }}</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block active_profile %}active{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<section id="user-profile" data-user-id="{{request.user.pk}}">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<h1 class="profile-name"><img src="{{ request.user.get_profile.profile_image_url }}" class="profile-image" /> {{user.first_name}}</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">Saldo</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<h2>{{request.user.get_profile.balance }} kr</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">Kjøp totalt</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<h2>{{orders_totals.sum }} kr</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">Topp 5 måneder</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
{% for o in top_months %}
|
||||||
|
<li>{{ o.month|date:"F Y"}}: <strong>{{ o.num }}</strong> kjøp på totalt <strong>{{ o.sum }} kr</strong></li>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">Kjøp over tid per produkt</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="profile-stats-orderline"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% comment %}<div class="row">
|
||||||
|
<div class="col-md-5">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">Ordre</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<ul>
|
||||||
|
{% for o in orders %}
|
||||||
|
<li>{{ o.created|date:"c" }}: {{ o.reciept }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">Transaksjoner</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<ul>
|
||||||
|
{% for t in transactions %}
|
||||||
|
<li>{{ t.created|date:"c" }} {{ t.amount }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endcomment %}
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
||||||
Reference in new issue
Block a user