Merge branch 'restfest'
This commit is contained in:
commit
e260b3d5bd
488 files changed
+1054
-97631
No files matched your search
Whitespace-only changes.
@@ -0,0 +1,39 @@
|
||||
from django.db.models import Sum, Count
|
||||
from rest_framework import serializers
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
|
||||
from main.models import Product, OrderLine, Order
|
||||
|
||||
|
||||
class ProductSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = Product
|
||||
|
||||
|
||||
class ProductStatSerializer(ModelSerializer):
|
||||
EXTERNAL_USER = 'Ekstern'
|
||||
counts = serializers.SerializerMethodField()
|
||||
|
||||
def _format_counts(self, per_user):
|
||||
per_user = list(per_user)
|
||||
for row in per_user:
|
||||
first = row.pop('order__customer__first_name')
|
||||
last = row.pop('order__customer__last_name')
|
||||
if first is None:
|
||||
who = self.EXTERNAL_USER
|
||||
else:
|
||||
who = '{} {}'.format(first, last)
|
||||
row['full_name'] = who
|
||||
|
||||
return per_user
|
||||
|
||||
def get_counts(self, obj):
|
||||
name_fields = ['order__customer__first_name', 'order__customer__last_name']
|
||||
per_user = OrderLine.objects.filter(product=obj)
|
||||
per_user = per_user.values(*name_fields).annotate(amount_total=Sum('amount')).order_by('-amount_total')
|
||||
|
||||
return self._format_counts(per_user)
|
||||
|
||||
class Meta:
|
||||
model = Product
|
||||
fields = ['id', 'name', 'description', 'image', 'inventory_amount', 'active', 'created', 'counts']
|
||||
@@ -0,0 +1,22 @@
|
||||
from rest_framework import mixins
|
||||
from rest_framework.decorators import list_route
|
||||
from rest_framework.response import Response
|
||||
|
||||
from main.api.serializers import ProductSerializer, ProductStatSerializer
|
||||
from main.models import Product
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
|
||||
|
||||
class ProductViewSet(mixins.ListModelMixin,
|
||||
mixins.RetrieveModelMixin,
|
||||
GenericViewSet):
|
||||
serializer_class = ProductSerializer
|
||||
queryset = Product.objects.all()
|
||||
|
||||
@list_route(methods=['get'])
|
||||
def group_by_user(self, request):
|
||||
products = self.get_queryset().filter(active=True)
|
||||
serializer = ProductStatSerializer(products, many=True)
|
||||
|
||||
return Response(serializer.data)
|
||||
|
||||
+26
-15
@@ -1,10 +1,11 @@
|
||||
from django.conf.urls import url
|
||||
|
||||
from main.views.stats import stats_list, stats_orders, stats_orders_hourly, stats_products_realtime, stats_products, \
|
||||
stats_products_per_user, products_json
|
||||
from django.conf.urls import url, patterns
|
||||
from main.api.views import ProductViewSet
|
||||
from main.views.stats import stats_list, stats_products_realtime, stats_products_per_user, \
|
||||
OrdersHourlyView, OrdersDailyView, OrdersMonthlyView, OrdersYearlyView
|
||||
from main.views.general import register, deposit, log
|
||||
from main.views.reports import inventory, inventory_add, report
|
||||
from main.views.users import create_user, profile
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', register, name='home'),
|
||||
@@ -12,17 +13,6 @@ urlpatterns = [
|
||||
url(r'^deposit/$', deposit, name='deposit'),
|
||||
url(r'^log/$', log, name='log'),
|
||||
url(r'^log/all$', log, kwargs={'limit': None}, name='log-all'),
|
||||
# Stats
|
||||
url(r'^stats/$', stats_list, name='stats'),
|
||||
url(r'^stats/orders/$', stats_orders, name='stats-orders'),
|
||||
url(r'^stats/orders/hourly$', stats_orders_hourly, name='stats-orders-hourly'),
|
||||
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/(?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'),
|
||||
# Products
|
||||
url(r'^products/(?P<product_id>[0-9]+)/$', products_json, name='json-product'),
|
||||
url(r'^products/$', products_json, name='json-products'),
|
||||
# Users
|
||||
url(r'^user/create/$', create_user, name='create-user'),
|
||||
url(r'^profile/$', profile, name='profile'),
|
||||
@@ -30,4 +20,25 @@ urlpatterns = [
|
||||
url(r'^inventory/$', inventory, name='inventory'),
|
||||
url(r'^inventory/add/$', inventory_add, name='inventory-add'),
|
||||
url(r'^report$', report, name='report'),
|
||||
|
||||
]
|
||||
# Stats
|
||||
urlpatterns += [
|
||||
url(r'^stats/$', stats_list, name='stats'),
|
||||
url(r'^stats/orders/hourly/$', OrdersHourlyView.as_view(), name='stats-orders-hourly'),
|
||||
url(r'^stats/orders/daily/', OrdersDailyView.as_view(), name='stats-orders-daily'),
|
||||
url(r'^stats/orders/monthly/', OrdersMonthlyView.as_view(), name='stats-orders-monthly'),
|
||||
url(r'^stats/orders/yearly/', OrdersYearlyView.as_view(), name='stats-orders-yearly'),
|
||||
url(r'^stats/orders/products_realtime$', stats_products_realtime, name='stats-products-realtime'),
|
||||
url(r'^stats/products/by_user/(?P<user_id>[0-9]+)/$', stats_products_per_user, name='stats-products-per-user'),
|
||||
]
|
||||
# Root level service-worker.js
|
||||
urlpatterns += patterns(
|
||||
'django.contrib.staticfiles.views',
|
||||
url(r'^service-worker\.js$', 'serve', kwargs={'path': 'dist/service-worker.js'})
|
||||
)
|
||||
|
||||
# API
|
||||
router = DefaultRouter()
|
||||
router.register(r'api/products', ProductViewSet)
|
||||
urlpatterns += router.urls
|
||||
+66
-102
@@ -1,133 +1,97 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
from django.db.models import Sum, Count
|
||||
from django.http import JsonResponse
|
||||
from django.shortcuts import render, get_object_or_404
|
||||
from django.shortcuts import render
|
||||
from django.utils import timezone
|
||||
from itertools import groupby
|
||||
|
||||
from django.utils import six
|
||||
from django.views.generic import View
|
||||
from main.models import Product, OrderLine, Order
|
||||
|
||||
|
||||
def stats_list(request):
|
||||
products = Product.objects.filter(active=True)
|
||||
order_groups = ['hourly', 'daily', 'monthly', 'yearly']
|
||||
|
||||
return render(request, 'stats.html', {'products': products})
|
||||
return render(request, 'stats.html', {'products': products, 'order_groups': order_groups})
|
||||
|
||||
|
||||
def serialize_product(product):
|
||||
f_product = {}
|
||||
for attr in Product._meta.get_all_field_names():
|
||||
if attr in ["transactions", "orderlines", "image"]:
|
||||
continue
|
||||
class OrdersView(View):
|
||||
grouping = 'orders'
|
||||
|
||||
if hasattr(product, attr) and product.__getattribute__(attr):
|
||||
if type(product.__getattribute__(attr)) is datetime:
|
||||
f_product[attr] = str(product.__getattribute__(attr))
|
||||
else:
|
||||
f_product[attr] = product.__getattribute__(attr)
|
||||
return f_product
|
||||
def get_range(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def get_key(self, order):
|
||||
raise NotImplementedError
|
||||
|
||||
def products_json(request, product_id=None):
|
||||
if product_id:
|
||||
# single
|
||||
products = get_object_or_404(Product, pk=product_id)
|
||||
else:
|
||||
# many
|
||||
products = Product.objects.filter(active=True)
|
||||
def group_by(self, orders):
|
||||
orders_grouped = dict([(key, 0) for key in self.get_range()]) # init
|
||||
for key, values in groupby(orders, key=self.get_key):
|
||||
count = len(list(values))
|
||||
orders_grouped[key] += count
|
||||
|
||||
if product_id:
|
||||
f_products = serialize_product(products)
|
||||
else:
|
||||
f_products = [serialize_product(product) for product in products]
|
||||
return orders_grouped
|
||||
|
||||
return JsonResponse(f_products)
|
||||
def get(self, request):
|
||||
orders = Order.objects.all()
|
||||
if not orders.exists():
|
||||
return JsonResponse({})
|
||||
|
||||
|
||||
def stats_product(product):
|
||||
# reverse lookup via order, customer
|
||||
per_user = OrderLine.objects\
|
||||
.filter(product=product)\
|
||||
.values('order__customer__first_name', 'order__customer__last_name')\
|
||||
.annotate(num=Sum('amount'))\
|
||||
.order_by('-num')
|
||||
f_per_user = []
|
||||
for row in per_user:
|
||||
if row['order__customer__first_name'] is not None:
|
||||
who = row['order__customer__first_name'] + " " + row['order__customer__last_name']
|
||||
else:
|
||||
who = "Ekstern"
|
||||
num = row['num']
|
||||
f_per_user.append([who, num])
|
||||
|
||||
response = {
|
||||
'product': serialize_product(Product.objects.get(pk=product)) if type(product) in six.string_types 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,
|
||||
orders_grouped = self.group_by(orders)
|
||||
data = {
|
||||
'start': str(orders[0].created),
|
||||
'orders': [[k, v] for k, v in orders_grouped.items()],
|
||||
'total': sum(orders_grouped.values()),
|
||||
'grouping': self.grouping
|
||||
}
|
||||
}
|
||||
return JsonResponse(response)
|
||||
return JsonResponse(data)
|
||||
|
||||
|
||||
def stats_orders(request):
|
||||
num_external_orders = Order.objects.filter(customer=None).count()
|
||||
per_user = Order.objects\
|
||||
.values('customer__first_name', 'customer__last_name')\
|
||||
.annotate(num=Count('customer'))\
|
||||
.order_by('num').reverse()
|
||||
f_per_user = []
|
||||
for row in per_user:
|
||||
if row['customer__first_name'] is not None:
|
||||
who = row['customer__first_name'] + " " + row['customer__last_name']
|
||||
num = row['num']
|
||||
else:
|
||||
who = "Ekstern"
|
||||
num = num_external_orders
|
||||
f_per_user.append([who, num])
|
||||
class OrdersHourlyView(OrdersView):
|
||||
grouping = 'hourly'
|
||||
|
||||
return JsonResponse(f_per_user, safe=False)
|
||||
def get_range(self):
|
||||
return range(0, 24)
|
||||
|
||||
def get_key(self, order):
|
||||
return order.created.hour
|
||||
|
||||
|
||||
def stats_orders_hourly(request):
|
||||
orders = Order.objects.all()
|
||||
f_hourly = dict([(key, 0) for key in range(0, 24)]) # init
|
||||
# group by hour
|
||||
for key, values in groupby(orders, key=lambda row: row.created.hour):
|
||||
count = len(list(values))
|
||||
f_hourly[key] += count
|
||||
class OrdersDailyView(OrdersView):
|
||||
grouping = 'daily'
|
||||
|
||||
if len(orders) == 0:
|
||||
return JsonResponse({})
|
||||
def get_range(self):
|
||||
return range(0, 7)
|
||||
|
||||
response = {
|
||||
'start': str(orders[0].created),
|
||||
'hourly': [[k, v] for k, v in f_hourly.items()],
|
||||
'total': sum(f_hourly.values()),
|
||||
}
|
||||
return JsonResponse(response)
|
||||
def get_key(self, order):
|
||||
return order.created.weekday()
|
||||
|
||||
|
||||
class OrdersMonthlyView(OrdersView):
|
||||
grouping = 'monthly'
|
||||
|
||||
def get_range(self):
|
||||
return range(1, 13)
|
||||
|
||||
def get_key(self, order):
|
||||
return order.created.month
|
||||
|
||||
|
||||
class OrdersYearlyView(OrdersView):
|
||||
grouping = 'yearly'
|
||||
|
||||
def get_range(self):
|
||||
first = Order.objects.order_by('created').first()
|
||||
last = timezone.now().year
|
||||
first = first.created.year if first else last
|
||||
|
||||
return range(first, last+1)
|
||||
|
||||
def get_key(self, order):
|
||||
return order.created.year
|
||||
|
||||
|
||||
def stats_products_realtime(request):
|
||||
|
||||
Reference in new issue
Block a user