Changeset - c64d0eaab857
[Not reviewed]
Merge
0 3 0
Christopher Neugebauer - 8 years ago 2016-09-03 03:53:09
chrisjrn@gmail.com
Merge branch 'chrisjrn/more_reports'
3 files changed with 76 insertions and 21 deletions:
0 comments (0 inline, 0 general)
registrasion/models/people.py
Show inline comments
...
 
@@ -46,43 +46,50 @@ class Attendee(models.Model):
 
    guided_categories_complete = models.ManyToManyField("category")
 

	
 

	
 
class AttendeeProfileBase(models.Model):
 
    ''' Information for an attendee's badge and related preferences.
 
    Subclass this in your Django site to ask for attendee information in your
 
    registration progess.
 
     '''
 

	
 
    class Meta:
 
        app_label = "registrasion"
 

	
 
    objects = InheritanceManager()
 

	
 
    @classmethod
 
    def name_field(cls):
 
        '''
 
        Returns:
 
            The name of a field that stores the attendee's name. This is used
 
            to pre-fill the attendee's name from their Speaker profile, if they
 
            have one.
 
        '''
 
        return None
 

	
 
    def attendee_name(self):
 
        if type(self) == AttendeeProfileBase:
 
            real = AttendeeProfileBase.objects.get_subclass(id=self.id)
 
        else:
 
            real = self
 
        return getattr(real, real.name_field())
 

	
 
    def invoice_recipient(self):
 
        '''
 

	
 
        Returns:
 
            A representation of this attendee profile for the purpose
 
            of rendering to an invoice. This should include any information
 
            that you'd usually include on an invoice. Override in subclasses.
 
        '''
 

	
 
        # Manual dispatch to subclass. Fleh.
 
        slf = AttendeeProfileBase.objects.get_subclass(id=self.id)
 
        # Actually compare the functions.
 
        if type(slf).invoice_recipient != type(self).invoice_recipient:
 
            return type(slf).invoice_recipient(slf)
 

	
 
        # Return a default
 
        return slf.attendee.user.username
 

	
 
    attendee = models.OneToOneField(Attendee, on_delete=models.CASCADE)
registrasion/reporting/views.py
Show inline comments
...
 
@@ -68,48 +68,84 @@ def items_sold(request, form):
 
        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("Reconcilitation")
 
def reconciliation(request, form):
 
    ''' Reconciles all sales in the system with the payments in the
 
    system. '''
 

	
 
    headings = ["Thing", "Total"]
 
    data = []
 

	
 
    sales = commerce.LineItem.objects.filter(
 
        invoice__status=commerce.Invoice.STATUS_PAID,
 
    ).values(
 
        "price", "quantity"
 
    ).aggregate(total=Sum(F("price") * F("quantity")))
 

	
 
    data.append(["Paid items", sales["total"]])
 

	
 
    payments = commerce.PaymentBase.objects.values(
 
        "amount",
 
    ).aggregate(total=Sum("amount"))
 

	
 
    data.append(["Payments", payments["total"]])
 

	
 
    ucn = commerce.CreditNote.unclaimed().values(
 
        "amount"
 
    ).aggregate(total=Sum("amount"))
 

	
 
    data.append(["Unclaimed credit notes", 0 - ucn["total"]])
 

	
 
    data.append([
 
        "(Money not on invoices)",
 
        sales["total"] - payments["total"] - ucn["total"],
 
    ])
 

	
 
    return Report("Sales and Payments", 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(),
 
        ),
 
    )
 

	
 
    items = items.order_by(
 
        "product__category__order",
 
        "product__order",
 
    ).values(
...
 
@@ -250,57 +286,76 @@ def attendee(request, form, attendee_id=None):
 
    )
 
    for invoice in invoices:
 
        data.append([
 
            invoice.id, invoice.get_status_display(), invoice.value,
 
        ])
 

	
 
    reports.append(Report("Invoices", headings, data, link_view="invoice"))
 

	
 
    # Credit Notes
 
    headings = ["Note ID", "Status", "Value"]
 
    data = []
 

	
 
    credit_notes = commerce.CreditNote.objects.filter(
 
        invoice__user=attendee.user,
 
    )
 
    for credit_note in credit_notes:
 
        data.append([
 
            credit_note.id, credit_note.status, credit_note.value,
 
        ])
 

	
 
    reports.append(
 
        Report("Credit Notes", headings, data, link_view="credit_note")
 
    )
 

	
 
    # All payments
 
    headings = ["To Invoice", "Payment ID", "Reference", "Amount"]
 
    data = []
 

	
 
    payments = commerce.PaymentBase.objects.filter(
 
        invoice__user=attendee.user,
 
    )
 
    for payment in payments:
 
        data.append([
 
            payment.invoice.id, payment.id, payment.reference, payment.amount,
 
        ])
 

	
 
    reports.append(
 
        Report("Payments", headings, data, link_view="invoice")
 
    )
 

	
 

	
 
    return reports
 

	
 

	
 
def attendee_list(request):
 
    ''' Returns a list of all attendees. '''
 

	
 
    attendees = people.Attendee.objects.all().select_related(
 
        "attendeeprofilebase",
 
        "user",
 
    )
 

	
 
    attendees = attendees.values("id", "user__email").annotate(
 
    attendees = attendees.annotate(
 
        has_registered=Count(
 
            Q(user__invoice__status=commerce.Invoice.STATUS_PAID)
 
        ),
 
    )
 

	
 
    headings = [
 
        "User ID", "Email", "Has registered",
 
        "User ID", "Name", "Email", "Has registered",
 
    ]
 

	
 
    data = []
 

	
 
    for attendee in attendees:
 
        data.append([
 
            attendee["id"],
 
            attendee["user__email"],
 
            attendee["has_registered"],
 
            attendee.id,
 
            attendee.attendeeprofilebase.attendee_name(),
 
            attendee.user.email,
 
            attendee.has_registered > 0,
 
        ])
 

	
 
    # Sort by whether they've registered, then ID.
 
    data.sort(key=lambda attendee: (-attendee[2], attendee[0]))
 
    data.sort(key=lambda attendee: (-attendee[3], attendee[0]))
 

	
 
    return Report("Attendees", headings, data, link_view="attendee")
registrasion/urls.py
Show inline comments
 
from reporting import views as reporting_views
 
from reporting import views as rv
 

	
 
from django.conf.urls import include
 
from django.conf.urls import url
 

	
 
from .views import (
 
    product_category,
 
    checkout,
 
    credit_note,
 
    invoice,
 
    manual_payment,
 
    refund,
 
    invoice_access,
 
    edit_profile,
 
    guided_registration,
 
)
 

	
 

	
 
public = [
 
    url(r"^category/([0-9]+)$", product_category, name="product_category"),
 
    url(r"^checkout$", checkout, name="checkout"),
 
    url(r"^credit_note/([0-9]+)$", credit_note, name="credit_note"),
 
    url(r"^invoice/([0-9]+)$", invoice, name="invoice"),
 
    url(r"^invoice/([0-9]+)/([A-Z0-9]+)$", invoice, name="invoice"),
 
    url(r"^invoice/([0-9]+)/manual_payment$",
 
        manual_payment, name="manual_payment"),
 
    url(r"^invoice/([0-9]+)/refund$",
 
        refund, name="refund"),
 
    url(r"^invoice_access/([A-Z0-9]+)$", invoice_access,
 
        name="invoice_access"),
 
    url(r"^profile$", edit_profile, name="attendee_edit"),
 
    url(r"^register$", guided_registration, name="guided_registration"),
 
    url(r"^register/([0-9]+)$", guided_registration,
 
        name="guided_registration"),
 
]
 

	
 

	
 
reports = [
 
    url(r"^$", reporting_views.reports_list, name="reports_list"),
 
    url(r"^attendee/?$", reporting_views.attendee, name="attendee"),
 
    url(r"^attendee/([0-9]*)$", reporting_views.attendee, name="attendee"),
 
    url(
 
        r"^credit_notes/?$",
 
        reporting_views.credit_notes,
 
        name="credit_notes"
 
    ),
 
    url(
 
        r"^product_status/?$",
 
        reporting_views.product_status,
 
        name="product_status",
 
    ),
 
    url(r"^items_sold/?$", reporting_views.items_sold, name="items_sold"),
 
    url(r"^$", rv.reports_list, name="reports_list"),
 
    url(r"^attendee/?$", rv.attendee, name="attendee"),
 
    url(r"^attendee/([0-9]*)$", rv.attendee, name="attendee"),
 
    url(r"^credit_notes/?$", rv.credit_notes, name="credit_notes"),
 
    url(r"^items_sold/?$", rv.items_sold, name="items_sold"),
 
    url(r"^product_status/?$", rv.product_status, name="product_status"),
 
    url(r"^reconciliation/?$", rv.reconciliation, name="reconciliation"),
 
]
 

	
 

	
 
urlpatterns = [
 
    url(r"^reports/", include(reports)),
 
    url(r"^", include(public))  # This one must go last.
 
]
0 comments (0 inline, 0 general)