Changeset - 2ed0a47f15bd
[Not reviewed]
0 3 0
Christopher Neugebauer - 8 years ago 2016-09-20 03:48:08
chrisjrn@gmail.com
Adds attendance by field report

Fixes #93
3 files changed with 119 insertions and 4 deletions:
0 comments (0 inline, 0 general)
registrasion/reporting/forms.py
Show inline comments
...
 
@@ -8,24 +8,43 @@ from django import forms
 

	
 
class DiscountForm(forms.Form):
 
    discount = forms.ModelMultipleChoiceField(
 
        queryset=conditions.DiscountBase.objects.all(),
 
        required=False,
 
    )
 

	
 

	
 
class ProductAndCategoryForm(forms.Form):
 
    product = forms.ModelMultipleChoiceField(
 
        queryset=inventory.Product.objects.all(),
 
        required=False,
 
    )
 
    category = forms.ModelMultipleChoiceField(
 
        queryset=inventory.Category.objects.all(),
 
        required=False,
 
    )
 

	
 

	
 
class UserIdForm(forms.Form):
 
    user = forms.IntegerField(
 
        label="User ID",
 
        required=False,
 
    )
 

	
 

	
 
def model_fields_form_factory(model):
 
    ''' Creates a form for specifying fields from a model to display. '''
 

	
 
    fields = model._meta.get_fields()
 

	
 
    choices = []
 
    for field in fields:
 
        if hasattr(field, "verbose_name"):
 
            choices.append((field.name, field.verbose_name))
 

	
 
    class ModelFieldsForm(forms.Form):
 
        fields = forms.MultipleChoiceField(
 
            choices=choices,
 
            required=False,
 
        )
 

	
 
    return ModelFieldsForm
registrasion/reporting/views.py
Show inline comments
...
 
@@ -343,48 +343,54 @@ def paid_invoices_by_date(request, form):
 
        ["date", "count"],
 
        data,
 
    )
 

	
 
@report_view("Credit notes")
 
def credit_notes(request, form):
 
    ''' Shows all of the credit notes in the system. '''
 

	
 
    notes = commerce.CreditNote.objects.all().select_related(
 
        "creditnoterefund",
 
        "creditnoteapplication",
 
        "invoice",
 
        "invoice__user__attendee__attendeeprofilebase",
 
    )
 

	
 
    return QuerysetReport(
 
        "Credit Notes",
 
        ["id", "invoice__user__attendee__attendeeprofilebase__invoice_recipient", "status", "value"],  # NOQA
 
        notes,
 
        headings=["id", "Owner", "Status", "Value"],
 
        link_view=views.credit_note,
 
    )
 

	
 

	
 
class AttendeeListReport(ListReport):
 

	
 
    def get_link(self, argument):
 
        return reverse(self._link_view) + "?user=%d" % int(argument)
 

	
 

	
 
@report_view("Attendee", form_type=forms.UserIdForm)
 
def attendee(request, form, user_id=None):
 
    ''' Returns a list of all manifested attendees if no attendee is specified,
 
    else displays the attendee manifest. '''
 

	
 
    if user_id is None and not form.has_changed():
 
        return attendee_list(request)
 

	
 
    if form.cleaned_data["user"] is not None:
 
        user_id = form.cleaned_data["user"]
 

	
 
    attendee = people.Attendee.objects.get(user__id=user_id)
 
    name = attendee.attendeeprofilebase.attendee_name()
 

	
 
    reports = []
 

	
 
    profile_data = []
 
    profile = people.AttendeeProfileBase.objects.get_subclass(
 
        attendee=attendee
 
    )
 
    exclude = set(["attendeeprofilebase_ptr", "id"])
 
    for field in profile._meta.get_fields():
 
        if field.name in exclude:
 
            # Not actually important
...
 
@@ -463,30 +469,119 @@ def attendee_list(request):
 

	
 
    attendees = attendees.annotate(
 
        has_registered=Count(
 
            Q(user__invoice__status=commerce.Invoice.STATUS_PAID)
 
        ),
 
    )
 

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

	
 
    data = []
 

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

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

	
 
    class Report(ListReport):
 
    return AttendeeListReport("Attendees", headings, data, link_view=attendee)
 

	
 

	
 
ProfileForm = forms.model_fields_form_factory(AttendeeProfile)
 
class ProductCategoryProfileForm(forms.ProductAndCategoryForm, ProfileForm):
 
    pass
 

	
 

	
 
@report_view(
 
    "Attendees By Product/Category",
 
    form_type=ProductCategoryProfileForm,
 
)
 
def attendee_data(request, form, user_id=None):
 
    ''' Lists attendees for a given product/category selection along with
 
    profile data.'''
 

	
 
    status_display = {
 
        commerce.Cart.STATUS_ACTIVE: "Unpaid",
 
        commerce.Cart.STATUS_PAID: "Paid",
 
        commerce.Cart.STATUS_RELEASED: "Refunded",
 
    }
 

	
 
    output = []
 

	
 
        def get_link(self, argument):
 
            return reverse(self._link_view) + "?user=%d" % int(argument)
 
    products = form.cleaned_data["product"]
 
    categories = form.cleaned_data["category"]
 
    fields = form.cleaned_data["fields"]
 
    name_field = AttendeeProfile.name_field()
 

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

	
 
    # Get all of the relevant attendee profiles in one hit.
 
    profiles = AttendeeProfile.objects.filter(
 
        attendee__user__cart__productitem__in=items
 
    ).select_related("attendee__user")
 
    by_user = {}
 
    for profile in profiles:
 
        by_user[profile.attendee.user] = profile
 

	
 
    for field in fields:
 
        field_verbose = AttendeeProfile._meta.get_field(field).verbose_name
 

	
 
        cart = "attendee__user__cart"
 
        cart_status = cart + "__status"
 
        product = cart + "__productitem__product"
 
        product_name = product + "__name"
 
        category_name = product + "__category__name"
 

	
 
        p = profiles.order_by(product, field).values(
 
            cart_status, product, product_name, category_name, field
 
        ).annotate(count=Count("id"))
 
        output.append(ListReport(
 
            "Grouped by %s" % field_verbose,
 
            ["Product", "Status", field_verbose, "count"],
 
            [
 
                (
 
                    "%s - %s" % (i[category_name], i[product_name]),
 
                    status_display[i[cart_status]],
 
                    i[field],
 
                    i["count"] or 0,
 
                )
 
                for i in p
 
            ],
 
        ))
 

	
 
    # DO the report for individual attendees
 

	
 
    field_names = [
 
        AttendeeProfile._meta.get_field(field).verbose_name for field in fields
 
    ]
 

	
 
    return Report("Attendees", headings, data, link_view=attendee)
 
    headings = ["User ID", "Name", "Product", "Item Status"] + field_names
 
    data = []
 
    for item in items:
 
        profile = by_user[item.cart.user]
 
        line = [
 
            item.cart.user.id,
 
            getattr(profile, name_field),
 
            item.product,
 
            status_display[item.cart.status],
 
        ] + [
 
            getattr(profile, field) for field in fields
 
        ]
 
        data.append(line)
 

	
 
    output.append(AttendeeListReport(
 
        "Attendees by item with profile data", headings, data, link_view=attendee
 
    ))
 
    return output
registrasion/urls.py
Show inline comments
...
 
@@ -22,41 +22,42 @@ public = [
 
    url(r"^amend/([0-9]+)$", amend_registration, name="amend_registration"),
 
    url(r"^category/([0-9]+)$", product_category, name="product_category"),
 
    url(r"^checkout$", checkout, name="checkout"),
 
    url(r"^checkout/([0-9]+)$", 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"^review$", review, name="review"),
 
    url(r"^register/([0-9]+)$", guided_registration,
 
        name="guided_registration"),
 
]
 

	
 

	
 
reports = [
 
    url(r"^$", rv.reports_list, name="reports_list"),
 
    url(r"^attendee/?$", rv.attendee, name="attendee"),
 
    url(r"^attendee_data/?$", rv.attendee_data, name="attendee_data"),
 
    url(r"^attendee/([0-9]*)$", rv.attendee, name="attendee"),
 
    url(r"^credit_notes/?$", rv.credit_notes, name="credit_notes"),
 
    url(r"^discount_status/?$", rv.discount_status, name="discount_status"),
 
    url(
 
        r"^paid_invoices_by_date/?$",
 
        rv.paid_invoices_by_date,
 
        name="paid_invoices_by_date"
 
    ),
 
    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)