You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

views.py 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. from decimal import Decimal as D
  2. from datetime import datetime, timedelta
  3. from django.views.generic import TemplateView
  4. from django.db.models.loading import get_model
  5. from django.db.models import Avg, Sum, Count
  6. from oscar.apps.offer.models import SITE
  7. ConditionalOffer = get_model('offer', 'ConditionalOffer')
  8. Voucher = get_model('voucher', 'Voucher')
  9. StockAlert = get_model('partner', 'StockAlert')
  10. Product = get_model('catalogue', 'Product')
  11. Order = get_model('order', 'Order')
  12. Line = get_model('order', 'Line')
  13. class IndexView(TemplateView):
  14. template_name = 'dashboard/index.html'
  15. def get_context_data(self, **kwargs):
  16. ctx = super(IndexView, self).get_context_data(**kwargs)
  17. ctx.update(self.get_stats())
  18. return ctx
  19. def get_active_site_offers(self):
  20. """
  21. Return active conditional offers of type "site offer". The returned
  22. ``Queryset`` of site offers is filtered by end date greater then
  23. the current date.
  24. """
  25. return ConditionalOffer.objects.filter(end_date__gt=datetime.now(),
  26. offer_type=SITE)
  27. def get_active_vouchers(self):
  28. """
  29. Get all active vouchers. The returned ``Queryset`` of vouchers
  30. is filtered by end date greater then the current date.
  31. """
  32. return Voucher.objects.filter(end_date__gt=datetime.now())
  33. def get_hourly_report(self, hours=24, segments=10):
  34. """
  35. Get report of order revenue split up in hourly chunks. A report is
  36. generated for the last *hours* (default=24) from the current time.
  37. The report provides ``max_revenue`` of the hourly order revenue sum,
  38. ``y-range`` as the labeling for the y-axis in a template and
  39. ``order_total_hourly``, a list of properties for hourly chunks.
  40. *segments* defines the number of labeling segments used for the y-axis
  41. when generating the y-axis labels (default=10).
  42. """
  43. # create report by the full hour
  44. time_now = datetime.now().replace(minute=0, second=0)
  45. # subtract 1 to make sure that the full hour is taken into account
  46. start_time = time_now - timedelta(hours=hours-1)
  47. orders_last_day = Order.objects.filter(date_placed__gt=start_time)
  48. order_total_hourly = []
  49. for hour in range(0, hours):
  50. end_time = start_time + timedelta(hours=1)
  51. hourly_orders = orders_last_day.filter(date_placed__gt=start_time,
  52. date_placed__lt=end_time)
  53. total = hourly_orders.aggregate(
  54. Sum('total_incl_tax')
  55. )['total_incl_tax__sum'] or D('0.0')
  56. order_total_hourly.append({
  57. 'end_time': end_time,
  58. 'total_incl_tax': total
  59. })
  60. start_time = end_time
  61. max_value = max([x['total_incl_tax'] for x in order_total_hourly])
  62. if max_value:
  63. segment_size = (max_value) / D('100.0')
  64. for item in order_total_hourly:
  65. item['percentage'] = int(item['total_incl_tax'] / segment_size)
  66. y_range = []
  67. y_axis_steps = max_value / D(str(segments))
  68. for idx in reversed(range(segments+1)):
  69. y_range.append(idx * y_axis_steps)
  70. else:
  71. y_range = []
  72. for item in order_total_hourly:
  73. item['percentage'] = 0
  74. return {
  75. 'order_total_hourly': order_total_hourly,
  76. 'max_revenue': max_value,
  77. 'y_range': y_range,
  78. }
  79. def get_stats(self):
  80. orders = Order.objects.filter()
  81. date_24hrs_ago = datetime.now() - timedelta(hours=24)
  82. orders_last_day = Order.objects.filter(date_placed__gt=date_24hrs_ago)
  83. open_alerts = StockAlert.objects.filter(status=StockAlert.OPEN)
  84. closed_alerts = StockAlert.objects.filter(status=StockAlert.CLOSED)
  85. stats = {
  86. 'total_orders_last_day': orders_last_day.count(),
  87. 'total_lines_last_day': orders_last_day.aggregate(
  88. Sum('lines')
  89. )['lines__sum'] or 0,
  90. 'average_order_costs': orders_last_day.aggregate(
  91. Avg('total_incl_tax')
  92. )['total_incl_tax__avg'] or D('0.00'),
  93. 'total_revenue_last_day': orders_last_day.aggregate(
  94. Sum('total_incl_tax')
  95. )['total_incl_tax__sum'] or D('0.00'),
  96. 'hourly_report_dict': self.get_hourly_report(hours=24),
  97. 'total_products': Product.objects.count(),
  98. 'total_open_stock_alerts': open_alerts.count(),
  99. 'total_closed_stock_alerts': closed_alerts.count(),
  100. 'total_site_offers': self.get_active_site_offers().count(),
  101. 'total_vouchers': self.get_active_vouchers().count(),
  102. 'total_orders': orders.count(),
  103. 'total_lines': Line.objects.filter(order__in=orders).count(),
  104. 'total_revenue': orders.aggregate(
  105. Sum('total_incl_tax')
  106. )['total_incl_tax__sum'] or D('0.00'),
  107. 'order_status_breakdown': orders.order_by(
  108. 'status'
  109. ).values('status').annotate(freq=Count('id'))
  110. }
  111. return stats