Makes the reporting framework a bit more DRY.

This commit is contained in:
Christopher Neugebauer 2016-08-26 15:11:08 +10:00
parent 3607fb19b8
commit 32b887fed3

View file

@ -31,22 +31,15 @@ A table
class Report(object): class Report(object):
def __init__(self, title, form, headings, data): def __init__(self, title, headings, data):
self._title = title
self._form = form
self._headings = headings self._headings = headings
self._data = data self._data = data
@property @property
def title(self): def title(self):
''' Returns the form. ''' ''' Returns the title for this report. '''
return self._title return self._title
@property
def form(self):
''' Returns the form. '''
return self._form
@property @property
def headings(self): def headings(self):
''' Returns the headings for the table. ''' ''' Returns the headings for the table. '''
@ -58,139 +51,136 @@ class Report(object):
return self._data return self._data
def report(view): def report(title, form_type):
''' Decorator that converts a report view function into something that ''' Decorator that converts a report view function into something that
displays a Report. displays a Report.
Arguments:
form_type: A form class that can make this report display things.
''' '''
@wraps(view) def _report(view):
def inner_view(request, *a, **k):
report = view(request, *a, **k)
ctx = { @wraps(view)
"title": report.title, def inner_view(request, *a, **k):
"form": report.form,
"report": report,
}
return render(request, "registrasion/report.html", ctx) form = form_type(request.GET)
if form.is_valid() and form.has_changed():
report = view(request, form, *a, **k)
else:
report = None
return inner_view ctx = {
"title": title,
"form": form,
"report": report,
}
return render(request, "registrasion/report.html", ctx)
return inner_view
return _report
@report @report("Paid items", forms.ProductAndCategoryForm)
def items_sold(request): def items_sold(request, form):
''' Summarises the items sold and discounts granted for a given set of ''' Summarises the items sold and discounts granted for a given set of
products, or products from categories. ''' products, or products from categories. '''
title = "Paid items"
form = forms.ProductAndCategoryForm(request.GET)
data = None data = None
headings = None headings = None
if form.is_valid() and form.has_changed(): products = form.cleaned_data["product"]
products = form.cleaned_data["product"] categories = form.cleaned_data["category"]
categories = form.cleaned_data["category"]
line_items = commerce.LineItem.objects.filter( line_items = commerce.LineItem.objects.filter(
Q(product__in=products) | Q(product__category__in=categories), Q(product__in=products) | Q(product__category__in=categories),
invoice__status=commerce.Invoice.STATUS_PAID, invoice__status=commerce.Invoice.STATUS_PAID,
).select_related("invoice") ).select_related("invoice")
line_items = line_items.order_by( line_items = line_items.order_by(
# sqlite requires an order_by for .values() to work # sqlite requires an order_by for .values() to work
"-price", "description", "-price", "description",
).values( ).values(
"price", "description", "price", "description",
).annotate( ).annotate(
total_quantity=Sum("quantity"), total_quantity=Sum("quantity"),
) )
print line_items print line_items
headings = ["Description", "Quantity", "Price", "Total"] 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 = []
total_income = 0
for line in line_items:
cost = line["total_quantity"] * line["price"]
data.append([ data.append([
"(TOTAL)", "--", "--", total_income, line["description"], line["total_quantity"],
line["price"], cost,
]) ])
total_income += cost
return Report(title, form, headings, data) data.append([
"(TOTAL)", "--", "--", total_income,
])
return Report("Paid items", headings, data)
@report @report("Inventory", forms.ProductAndCategoryForm)
def inventory(request): def inventory(request, form):
''' Summarises the inventory status of the given items, grouping by ''' Summarises the inventory status of the given items, grouping by
invoice status. ''' invoice status. '''
title = "Inventory" products = form.cleaned_data["product"]
categories = form.cleaned_data["category"]
form = forms.ProductAndCategoryForm(request.GET) items = commerce.ProductItem.objects.filter(
Q(product__in=products) | Q(product__category__in=categories),
).select_related("cart", "product")
data = None # TODO annotate with whether the item is reserved or not.
headings = None
if form.is_valid() and form.has_changed(): items = items.annotate(is_reserved=Case(
products = form.cleaned_data["product"] When(cart__in=commerce.Cart.reserved_carts(), then=Value(1)),
categories = form.cleaned_data["category"] default=Value(0),
output_field=models.BooleanField(),
))
items = commerce.ProductItem.objects.filter( items = items.order_by(
Q(product__in=products) | Q(product__category__in=categories), "cart__status",
).select_related("cart", "product") "product__category__order",
"product__order",
).values(
"product",
"product__category__name",
"product__name",
"cart__status",
"is_reserved",
).annotate(
total_quantity=Sum("quantity"),
)
# TODO annotate with whether the item is reserved or not. headings = ["Product", "Status", "Quantity"]
data = []
items = items.annotate(is_reserved=Case( def status(reserved, status):
When(cart__in=commerce.Cart.reserved_carts(), then=Value(1)), r = "Reserved" if reserved else "Unreserved"
default=Value(0), # This is a bit weird -- can we simplify?
output_field=models.BooleanField(), s = "".join(
)) "%s" % i[1] for i in commerce.Cart.STATUS_TYPES if i[0]==status
items = items.order_by(
"cart__status",
"product__category__order",
"product__order",
).values(
"product",
"product__category__name",
"product__name",
"cart__status",
"is_reserved",
).annotate(
total_quantity=Sum("quantity"),
) )
return "%s - %s" % (r, s)
headings = ["Product", "Status", "Quantity"] for item in items:
data = [] data.append([
"%s - %s" % (
item["product__category__name"], item["product__name"]
),
status(item["is_reserved"], item["cart__status"]),
item["total_quantity"],
])
def status(reserved, status): return Report("Inventory", headings, data)
r = "Reserved" if reserved else "Unreserved"
s = "".join(
"%s" % i[1]
for i in commerce.Cart.STATUS_TYPES if i[0]==status
)
return "%s - %s" % (r, s)
for item in items:
print commerce.Cart.STATUS_TYPES
data.append([
"%s - %s" % (
item["product__category__name"], item["product__name"]
),
status(item["is_reserved"], item["cart__status"]),
item["total_quantity"],
])
return Report(title, form, headings, data)