Adds initial profile page

This commit is contained in:
nikolark committed 2014-10-11 17:03:58 +02:00
1 parent fc65e15d98
commit f8a94b7bee
10 files changed
+195 -22

No files matched your search

+9 -6
View File
@@ -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()
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
});
});
}
}); });
+10
View File
@@ -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;
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1
View File
@@ -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 %}
+3 -3
View File
@@ -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>
+71
View File
@@ -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 %}