Changeset - 25608b1653e7
[Not reviewed]
0 2 1
Christopher Neugebauer - 8 years ago 2016-09-02 04:33:23
chrisjrn@gmail.com
Moves reports forms into reporting sub package
3 files changed with 17 insertions and 14 deletions:
0 comments (0 inline, 0 general)
registrasion/forms.py
Show inline comments
...
 
@@ -254,109 +254,96 @@ class _ItemQuantityProductsForm(_ProductsForm):
 
    def initial_data(cls, product_quantities):
 
        initial = {}
 

	
 
        for product, quantity in product_quantities:
 
            if quantity > 0:
 
                initial[cls.CHOICE_FIELD] = product.id
 
                initial[cls.QUANTITY_FIELD] = quantity
 
                break
 

	
 
        return initial
 

	
 
    def product_quantities(self):
 
        our_choice = self.cleaned_data[self.CHOICE_FIELD]
 
        our_quantity = self.cleaned_data[self.QUANTITY_FIELD]
 
        choices = self.fields[self.CHOICE_FIELD].choices
 
        for choice_value, choice_display in choices:
 
            if choice_value == 0:
 
                continue
 
            yield (
 
                choice_value,
 
                our_quantity if our_choice == choice_value else 0,
 
            )
 

	
 
    def add_product_error(self, product, error):
 
        if self.CHOICE_FIELD not in self.cleaned_data:
 
            return
 

	
 
        if product.id == self.cleaned_data[self.CHOICE_FIELD]:
 
            self.add_error(self.CHOICE_FIELD, error)
 
            self.add_error(self.QUANTITY_FIELD, error)
 

	
 

	
 
class _ItemQuantityProductsFormSet(_HasProductsFields, forms.BaseFormSet):
 

	
 
    @classmethod
 
    def set_fields(cls, category, products):
 
        raise ValueError("set_fields must be called on the underlying Form")
 

	
 
    @classmethod
 
    def initial_data(cls, product_quantities):
 
        ''' Prepares initial data for an instance of this form.
 
        product_quantities is a sequence of (product,quantity) tuples '''
 

	
 
        f = [
 
            {
 
                _ItemQuantityProductsForm.CHOICE_FIELD: product.id,
 
                _ItemQuantityProductsForm.QUANTITY_FIELD: quantity,
 
            }
 
            for product, quantity in product_quantities
 
            if quantity > 0
 
        ]
 
        return f
 

	
 
    def product_quantities(self):
 
        ''' Yields a sequence of (product, quantity) tuples from the
 
        cleaned form data. '''
 

	
 
        products = set()
 
        # Track everything so that we can yield some zeroes
 
        all_products = set()
 

	
 
        for form in self:
 
            if form.empty_permitted and not form.cleaned_data:
 
                # This is the magical empty form at the end of the list.
 
                continue
 

	
 
            for product, quantity in form.product_quantities():
 
                all_products.add(product)
 
                if quantity == 0:
 
                    continue
 
                if product in products:
 
                    form.add_error(
 
                        _ItemQuantityProductsForm.CHOICE_FIELD,
 
                        "You may only choose each product type once.",
 
                    )
 
                    form.add_error(
 
                        _ItemQuantityProductsForm.QUANTITY_FIELD,
 
                        "You may only choose each product type once.",
 
                    )
 
                products.add(product)
 
                yield product, quantity
 

	
 
        for product in (all_products - products):
 
            yield product, 0
 

	
 
    def add_product_error(self, product, error):
 
        for form in self.forms:
 
            form.add_product_error(product, error)
 

	
 

	
 
class VoucherForm(forms.Form):
 
    voucher = forms.CharField(
 
        label="Voucher code",
 
        help_text="If you have a voucher code, enter it here",
 
        required=False,
 
    )
 

	
 

	
 
# Staff-facing forms.
 

	
 
class ProductAndCategoryForm(forms.Form):
 
    product = forms.ModelMultipleChoiceField(
 
        queryset=inventory.Product.objects.all(),
 
        required=False,
 
    )
 
    category = forms.ModelMultipleChoiceField(
 
        queryset=inventory.Category.objects.all(),
 
        required=False,
 
    )
registrasion/reporting/forms.py
Show inline comments
 
new file 100644
 
from registrasion.models import inventory
 

	
 
from django import forms
 

	
 
# Staff-facing forms.
 

	
 
class ProductAndCategoryForm(forms.Form):
 
    product = forms.ModelMultipleChoiceField(
 
        queryset=inventory.Product.objects.all(),
 
        required=False,
 
    )
 
    category = forms.ModelMultipleChoiceField(
 
        queryset=inventory.Category.objects.all(),
 
        required=False,
 
    )
registrasion/reporting/views.py
Show inline comments
 
import forms
 

	
 
from django.contrib.auth.decorators import user_passes_test
 
from django.core.urlresolvers import reverse
 
from django.db import models
 
from django.db.models import F, Q
 
from django.db.models import Sum
 
from django.db.models import Case, When, Value
 
from django.shortcuts import render
 

	
 
from registrasion import forms
 
from registrasion.models import commerce
 
from registrasion import views
 

	
 
from reports import get_all_reports
 
from reports import Report
 
from reports import report_view
 

	
 

	
 
@user_passes_test(views._staff_only)
 
def reports_list(request):
 
    ''' Lists all of the reports currently available. '''
 

	
 
    reports = []
 

	
 
    for report in get_all_reports():
 
        reports.append({
 
            "name": report.__name__,
 
            "url": reverse(report),
 
            "description": report.__doc__,
 
        })
 

	
 
    reports.sort(key=lambda report: report["name"])
 

	
 
    ctx = {
 
        "reports": reports,
 
    }
 

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

	
 

	
 
# Report functions
 

	
 

	
 
@report_view("Paid items", form_type=forms.ProductAndCategoryForm)
 
def items_sold(request, form):
 
    ''' Summarises the items sold and discounts granted for a given set of
 
    products, or products from categories. '''
 

	
 
    data = None
 
    headings = None
 

	
 
    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("Paid items", headings, data)
 

	
 

	
 
@report_view("Product status", form_type=forms.ProductAndCategoryForm)
 
def product_status(request, form):
 
    ''' Summarises the inventory status of the given items, grouping by
 
    invoice status. '''
 

	
 
    products = form.cleaned_data["product"]
 
    categories = form.cleaned_data["category"]
 

	
 
    items = commerce.ProductItem.objects.filter(
 
        Q(product__in=products) | Q(product__category__in=categories),
 
    ).select_related("cart", "product")
 

	
 
    items = items.annotate(
 
        is_reserved=Case(
 
            When(cart__in=commerce.Cart.reserved_carts(), then=Value(1)),
 
            default=Value(0),
 
            output_field=models.BooleanField(),
0 comments (0 inline, 0 general)