<commit_before>import forms

from django.db.models import Q
from django.db.models import Sum
from django.shortcuts import render
from functools import wraps

from models import commerce


'''

All reports must be viewable by staff only (permissions?)

Reports can have:

A form
 * Reports are all *gettable* - you can save a URL and get back to the same
 report
 * Fetching a report *cannot* break the underlying data.
A table
 * Headings
 * Data lines
 * Formats are pluggable

'''


class Report(object):

    def __init__(self, title, form, headings, data):
        self._title = title
        self._form = form
        self._headings = headings
        self._data = data

    @property
    def title(self):
        ''' Returns the form. '''
        return self._title

    @property
    def form(self):
        ''' Returns the form. '''
        return self._form

    @property
    def headings(self):
        ''' Returns the headings for the table. '''
        return self._headings

    @property
    def data(self):
        ''' Returns the data rows for the table. '''
        return self._data


def report(view):
    ''' Decorator that converts a report view function into something that
    displays a Report.

    '''

    @wraps(view)
    def inner_view(request, *a, **k):
        report = view(request, *a, **k)

        ctx = {
            "title": report.title,
            "form": report.form,
            "report": report,
        }

        return render(request, "registrasion/report.html", ctx)

    return inner_view


@report
def items_sold(request):
    ''' Summarises the items sold and discounts granted for a given set of
    products, or products from categories. '''

    title = "Paid items"

    form = forms.ProductAndCategoryForm(request.GET)

    data = None
    headings = None

    if form.is_valid() and form.has_changed():
        products = form.cleaned_data["product"]
        categories = form.cleaned_data["category"]

        line_items = commerce.LineItem.objects.filter(
            Q(product__in=products) | Q(product__category__in=categories),
            invoice__status=commerce.Invoice.STATUS_PAID,
        ).select_related("invoice")

        line_items = line_items.order_by(
            # sqlite requires an order_by for .values() to work
            "-price", "description",
        ).values(
            "price", "description",
        ).annotate(
            total_quantity=Sum("quantity"),
        )

        print line_items

        headings = ["description", "quantity", "price", "total"]

        data = []
        for line in line_items:
            data.append([
                line["description"], line["total_quantity"],
                line["price"], line["total_quantity"] * line["price"],
            ])

    return Report(title, form, headings, data)<commit_msg>Makes the sales report keep a total.<commit_after>import forms

from django.db.models import Q
from django.db.models import Sum
from django.shortcuts import render
from functools import wraps

from models import commerce


'''

All reports must be viewable by staff only (permissions?)

Reports can have:

A form
 * Reports are all *gettable* - you can save a URL and get back to the same
 report
 * Fetching a report *cannot* break the underlying data.
A table
 * Headings
 * Data lines
 * Formats are pluggable

'''


class Report(object):

    def __init__(self, title, form, headings, data):
        self._title = title
        self._form = form
        self._headings = headings
        self._data = data

    @property
    def title(self):
        ''' Returns the form. '''
        return self._title

    @property
    def form(self):
        ''' Returns the form. '''
        return self._form

    @property
    def headings(self):
        ''' Returns the headings for the table. '''
        return self._headings

    @property
    def data(self):
        ''' Returns the data rows for the table. '''
        return self._data


def report(view):
    ''' Decorator that converts a report view function into something that
    displays a Report.

    '''

    @wraps(view)
    def inner_view(request, *a, **k):
        report = view(request, *a, **k)

        ctx = {
            "title": report.title,
            "form": report.form,
            "report": report,
        }

        return render(request, "registrasion/report.html", ctx)

    return inner_view


@report
def items_sold(request):
    ''' Summarises the items sold and discounts granted for a given set of
    products, or products from categories. '''

    title = "Paid items"

    form = forms.ProductAndCategoryForm(request.GET)

    data = None
    headings = None

    if form.is_valid() and form.has_changed():
        products = form.cleaned_data["product"]
        categories = form.cleaned_data["category"]

        line_items = commerce.LineItem.objects.filter(
            Q(product__in=products) | Q(product__category__in=categories),
            invoice__status=commerce.Invoice.STATUS_PAID,
        ).select_related("invoice")

        line_items = line_items.order_by(
            # sqlite requires an order_by for .values() to work
            "-price", "description",
        ).values(
            "price", "description",
        ).annotate(
            total_quantity=Sum("quantity"),
        )

        print line_items

        headings = ["description", "quantity", "price", "total"]

        data = []
        total_income = 0
        for line in line_items:
            cost = line["total_quantity"] * line["price"]
            data.append([
                line["description"], line["total_quantity"],
                line["price"], cost,
            ])
            total_income += cost

        data.append([
            "(TOTAL)", "--", "--", total_income,
        ])

    return Report(title, form, headings, data)
{'fraction_non_alphanumeric': 0.10666666666666667, 'fraction_numerical': 0.00017094017094017094, 'mean_word_length': 2.2742025741466145, 'pattern_counts': {'":': 6, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '331063', 'n_tokens_mistral': 1665, 'n_tokens_neox': 1584, 'n_words': 502}