| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- from datetime import timedelta
- from decimal import Decimal as D, ROUND_UP
-
- from django.utils.timezone import now
- from django.views.generic import TemplateView
- from django.db.models.loading import get_model
- from django.db.models import Avg, Sum, Count
- from django.contrib.auth.models import User
-
- from oscar.apps.basket.abstract_models import OPEN as basket_OPEN
- from oscar.apps.promotions.models import AbstractPromotion
-
- ConditionalOffer = get_model('offer', 'ConditionalOffer')
- Voucher = get_model('voucher', 'Voucher')
- Basket = get_model('basket', 'Basket')
- StockAlert = get_model('partner', 'StockAlert')
- Product = get_model('catalogue', 'Product')
- Order = get_model('order', 'Order')
- Line = get_model('order', 'Line')
-
-
- class IndexView(TemplateView):
- template_name = 'dashboard/index.html'
-
- def get_context_data(self, **kwargs):
- ctx = super(IndexView, self).get_context_data(**kwargs)
- ctx.update(self.get_stats())
- return ctx
-
- def get_active_site_offers(self):
- """
- Return active conditional offers of type "site offer". The returned
- ``Queryset`` of site offers is filtered by end date greater then
- the current date.
- """
- return ConditionalOffer.objects.filter(end_date__gt=now(),
- offer_type=ConditionalOffer.SITE)
-
- def get_active_vouchers(self):
- """
- Get all active vouchers. The returned ``Queryset`` of vouchers
- is filtered by end date greater then the current date.
- """
- return Voucher.objects.filter(end_date__gt=now())
-
- def get_number_of_promotions(self, abstract_base=AbstractPromotion):
- """
- Get the number of promotions for all promotions derived from
- *abstract_base*. All subclasses of *abstract_base* are queried
- and if another abstract base class is found this method is executed
- recursively.
- """
- total = 0
- for cls in abstract_base.__subclasses__():
- if cls._meta.abstract:
- total += self.get_number_of_promotions(cls)
- else:
- total += cls.objects.count()
- return total
-
- def get_open_baskets(self, filters=None):
- """
- Get all open baskets. If *filters* dictionary is provided they will
- be applied on all open baskets and return only filtered results.
- """
- if filters is None:
- filters = {}
- filters['status'] = basket_OPEN
- return Basket.objects.filter(**filters)
-
- def get_hourly_report(self, hours=24, segments=10):
- """
- Get report of order revenue split up in hourly chunks. A report is
- generated for the last *hours* (default=24) from the current time.
- The report provides ``max_revenue`` of the hourly order revenue sum,
- ``y-range`` as the labeling for the y-axis in a template and
- ``order_total_hourly``, a list of properties for hourly chunks.
- *segments* defines the number of labeling segments used for the y-axis
- when generating the y-axis labels (default=10).
- """
- # Get datetime for 24 hours agao
- time_now = now().replace(minute=0, second=0)
- start_time = time_now - timedelta(hours=hours-1)
-
- orders_last_day = Order.objects.filter(date_placed__gt=start_time)
-
- order_total_hourly = []
- for hour in range(0, hours):
- end_time = start_time + timedelta(hours=1)
- hourly_orders = orders_last_day.filter(date_placed__gt=start_time,
- date_placed__lt=end_time)
- total = hourly_orders.aggregate(
- Sum('total_incl_tax')
- )['total_incl_tax__sum'] or D('0.0')
- order_total_hourly.append({
- 'end_time': end_time,
- 'total_incl_tax': total
- })
- start_time = end_time
-
- max_value = max([x['total_incl_tax'] for x in order_total_hourly])
- divisor = 1
- while divisor < max_value / 50:
- divisor *= 10
- max_value = (max_value / divisor).quantize(D('1'), rounding=ROUND_UP)
- max_value *= divisor
- if max_value:
- segment_size = (max_value) / D('100.0')
- for item in order_total_hourly:
- item['percentage'] = int(item['total_incl_tax'] / segment_size)
-
- y_range = []
- y_axis_steps = max_value / D(str(segments))
- for idx in reversed(range(segments+1)):
- y_range.append(idx * y_axis_steps)
- else:
- y_range = []
- for item in order_total_hourly:
- item['percentage'] = 0
-
- ctx = {
- 'order_total_hourly': order_total_hourly,
- 'max_revenue': max_value,
- 'y_range': y_range,
- }
- return ctx
-
- def get_stats(self):
- datetime_24hrs_ago = now() - timedelta(hours=24)
-
- orders = Order.objects.filter()
- orders_last_day = orders.filter(date_placed__gt=datetime_24hrs_ago)
-
- open_alerts = StockAlert.objects.filter(status=StockAlert.OPEN)
- closed_alerts = StockAlert.objects.filter(status=StockAlert.CLOSED)
-
- stats = {
- 'total_orders_last_day': orders_last_day.count(),
- 'total_lines_last_day': Line.objects.filter(order__in=orders_last_day).count(),
-
- 'average_order_costs': orders_last_day.aggregate(
- Avg('total_incl_tax')
- )['total_incl_tax__avg'] or D('0.00'),
-
- 'total_revenue_last_day': orders_last_day.aggregate(
- Sum('total_incl_tax')
- )['total_incl_tax__sum'] or D('0.00'),
-
- 'hourly_report_dict': self.get_hourly_report(hours=24),
- 'total_customers_last_day': User.objects.filter(
- date_joined__gt=datetime_24hrs_ago,
- ).count(),
-
- 'total_open_baskets_last_day': self.get_open_baskets({
- 'date_created__gt': datetime_24hrs_ago
- }).count(),
-
- 'total_products': Product.objects.count(),
- 'total_open_stock_alerts': open_alerts.count(),
- 'total_closed_stock_alerts': closed_alerts.count(),
-
- 'total_site_offers': self.get_active_site_offers().count(),
- 'total_vouchers': self.get_active_vouchers().count(),
- 'total_promotions': self.get_number_of_promotions(),
-
- 'total_customers': User.objects.count(),
- 'total_open_baskets': self.get_open_baskets().count(),
- 'total_orders': orders.count(),
- 'total_lines': Line.objects.filter(order__in=orders).count(),
- 'total_revenue': orders.aggregate(
- Sum('total_incl_tax')
- )['total_incl_tax__sum'] or D('0.00'),
-
- 'order_status_breakdown': orders.order_by(
- 'status'
- ).values('status').annotate(freq=Count('id'))
- }
- return stats
|