CodeTheChangeUBC/reBOOT

View on GitHub
app/views/data_view.py

Summary

Maintainability
A
0 mins
Test Coverage
# -*- coding: utf-8 -*-
from django.contrib.auth.decorators import login_required
from django.db.models import Count, F, FloatField, Sum
from django.http import HttpResponseBadRequest, JsonResponse
from django.views.decorators.http import require_GET

from app.models import Donation, Donor, Item


@require_GET
@login_required(login_url='/login')
def aggregate_value(request):
    """Return JSON of array of values of request.GET['model'] for given
    interval of request.GET['startDate'] and request.GET['endDate']. The
    default response is for items from all time.
    """
    try:
        model = request.GET.get('model', 'item')
        start_date = request.GET.get('startDate', None)
        end_date = request.GET.get('endDate', None)

        items = __getQuerysetGivenInterval(model, start_date, end_date)

        agg_values = list(items.values('documented_at')
                               .annotate(
                                   total_value=Sum(
                                       F('value') * F('quantity'),
                                       output_field=FloatField())))
        result = {'result': __castDecimalToFloat(agg_values)}

        return JsonResponse(result, status=200)
    except BaseException as e:
        print(e.args)
        return HttpResponseBadRequest()


@require_GET
@login_required(login_url='/login')
def aggregate_quantity(request):
    """Return JSON of aggregate quantity of given model for given time interval."""
    try:
        model = request.GET['model']
        start_date = request.GET.get('startDate', None)
        end_date = request.GET.get('endDate', None)

        items = __getQuerysetGivenInterval(model, start_date, end_date)

        # Count all models as 1 except for items which has quantity field
        count_method = Count('pk') if model != 'item' else Sum('quantity')

        agg_qty = list(items.values('documented_at')
                            .annotate(total_quantity=count_method))
        result = {'result': agg_qty}

        return JsonResponse(result, status=200)
    except BaseException as e:
        print(e.args)
        return HttpResponseBadRequest()


@require_GET
@login_required(login_url='/login')
def aggregate_status(request):
    """Return aggregate status of item for given time interval."""
    try:
        model = 'item'
        start_date = request.GET.get('startDate', None)
        end_date = request.GET.get('endDate', None)

        items = __getQuerysetGivenInterval(model, start_date, end_date)

        agg_status = list(items.values('status')
                               .annotate(count=Count('status')))

        result = {'result': agg_status}

        return JsonResponse(result, status=200)
    except BaseException as e:
        print(e.args)
        return HttpResponseBadRequest()


@require_GET
@login_required(login_url='/login')
def aggregate_location(request):
    """Return a JSON of province and item_quantity"""
    try:
        start_date = request.GET.get('startDate', None)
        end_date = request.GET.get('endDate', None)

        items = __getQuerysetGivenInterval('item', start_date, end_date)

        items_grouped_by_location = list(
            items.annotate(location=F('donation__donor__city'))
            .values('location')
            .annotate(count=Count('location'))
        )
        result = {'result': items_grouped_by_location}

        return JsonResponse(result, status=200)
    except BaseException as e:
        print(e.args)
        return HttpResponseBadRequest()


"""
Private
"""


def __getQuerysetGivenInterval(model, start_date, end_date):
    """Returns the given Models in given time interval."""
    cur_model = {
        'donor': Donor,
        'donation': Donation,
        'item': Item
    }.get(model, Donor.objects.none())

    # might need following lines when changing back to created_at:
    # date_format = "%Y-%m-%d"
    # if start_date is not None:
    #     timezone_unaware_start_date = datetime.strptime(start_date, date_format)
    #     timezone_aware_start_date = pytz.utc.localize(timezone_unaware_start_date)
    #
    # if end_date is not None:
    #     timezone_unaware_end_date = datetime.strptime(end_date, date_format)
    #     timezone_aware_end_date = pytz.utc.localize(timezone_unaware_end_date).date()

    if start_date is not None and end_date is not None:
        return cur_model.objects.filter(
            documented_at__range=(
                start_date, end_date))
    elif start_date is not None and end_date is None:
        return cur_model.objects.filter(documented_at__gte=start_date)
    elif start_date is None and end_date is not None:
        return cur_model.objects.filter(documented_at__lte=end_date)
    else:
        return cur_model.objects.all()


def __castDecimalToFloat(lists):
    for pair in lists:
        pair['total_value'] = float(
            "{:.2f}".format(float(pair['total_value'])))
    return lists