registrasion/reporting/views.py
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 = []

    by_category = (
        form.cleaned_data["group_by"] == forms.GroupByForm.GROUP_BY_CATEGORY)

    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", "cart__user", "product", "product__category",
    ).order_by("cart__status")

    # Add invoice nag link
    links = []
    invoice_mailout = reverse(views.invoice_mailout, args=[])
    invoice_mailout += "?" + request.META["QUERY_STRING"]
    links += [
        (invoice_mailout + "&status=1", "Send invoice reminders",),
        (invoice_mailout + "&status=2", "Send mail for paid invoices",),
    ]

    if items.count() > 0:
        output.append(Links("Actions", links))

    # Make sure we select all of the related fields
    related_fields = set(
        field for field in fields
        if isinstance(AttendeeProfile._meta.get_field(field), RelatedField)
    )

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

    cart = "attendee__user__cart"
    cart_status = cart + "__status"  # noqa
    product = cart + "__productitem__product"
    product_name = product + "__name"
    category = product + "__category"
    category_name = category + "__name"

    if by_category:
        grouping_fields = (category, category_name)
        order_by = (category, )
        first_column = "Category"
        group_name = lambda i: "%s" % (i[category_name], )  # noqa
    else:
        grouping_fields = (product, product_name, category_name)
        order_by = (category, )
        first_column = "Product"
        group_name = lambda i: "%s - %s" % (i[category_name], i[product_name])  # noqa

    # Group the responses per-field.
    for field in fields:
        concrete_field = AttendeeProfile._meta.get_field(field)
        field_verbose = concrete_field.verbose_name

        # Render the correct values for related fields
        if field in related_fields:
            # Get all of the IDs that will appear
            all_ids = profiles.order_by(field).values(field)
            all_ids = [i[field] for i in all_ids if i[field] is not None]
            # Get all of the concrete objects for those IDs
            model = concrete_field.related_model
            all_objects = model.objects.filter(id__in=all_ids)
            all_objects_by_id = dict((i.id, i) for i in all_objects)

            # Define a function to render those IDs.
            def display_field(value):
                if value in all_objects_by_id:
                    return all_objects_by_id[value]
                else:
                    return None
        else:
            def display_field(value):
                return value

        status_count = lambda status: Case(When(  # noqa
                attendee__user__cart__status=status,
                then=Value(1),
            ),
            default=Value(0),
            output_field=models.fields.IntegerField(),
        )
        paid_count = status_count(commerce.Cart.STATUS_PAID)
        unpaid_count = status_count(commerce.Cart.STATUS_ACTIVE)

        groups = profiles.order_by(
            *(order_by + (field, ))
        ).values(
            *(grouping_fields + (field, ))
        ).annotate(
            paid_count=Sum(paid_count),
            unpaid_count=Sum(unpaid_count),
        )
        output.append(ListReport(
            "Grouped by %s" % field_verbose,
            [first_column, field_verbose, "paid", "unpaid"],
            [
                (
                    group_name(group),
                    display_field(group[field]),
                    group["paid_count"] or 0,
                    group["unpaid_count"] or 0,
                )
                for group in groups
            ],
        ))

    # DO the report for individual attendees

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

    def display_field(profile, field):
        field_type = AttendeeProfile._meta.get_field(field)
        attr = getattr(profile, field)

        if isinstance(field_type, models.ManyToManyField):
            return [str(i) for i in attr.all()] or ""
        else:
            return attr

    headings = ["User ID", "Name", "Email", "Product", "Item Status"]
    headings.extend(field_names)
    data = []
    for item in items:
        profile = by_user[item.cart.user]
        line = [
            item.cart.user.id,
            getattr(profile, name_field),
            profile.attendee.user.email,
            item.product,
            status_display[item.cart.status],
        ] + [
            display_field(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
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 = []

    by_category = (
        form.cleaned_data["group_by"] == forms.GroupByForm.GROUP_BY_CATEGORY)

    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", "cart__user", "product", "product__category",
    ).order_by("cart__status")

    # Add invoice nag link
    links = []
    invoice_mailout = reverse(views.invoice_mailout, args=[])
    invoice_mailout += "?" + request.META["QUERY_STRING"]
    links += [
        (invoice_mailout + "&status=1", "Send invoice reminders",),
        (invoice_mailout + "&status=2", "Send mail for paid invoices",),
    ]

    if items.count() > 0:
        output.append(Links("Actions", links))

    # Make sure we select all of the related fields
    related_fields = set(
        field for field in fields
        if isinstance(AttendeeProfile._meta.get_field(field), RelatedField)
    )

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

    cart = "attendee__user__cart"
    cart_status = cart + "__status"  # noqa
    product = cart + "__productitem__product"
    product_name = product + "__name"
    category = product + "__category"
    category_name = category + "__name"

    if by_category:
        grouping_fields = (category, category_name)
        order_by = (category, )
        first_column = "Category"
        group_name = lambda i: "%s" % (i[category_name], )  # noqa
    else:
        grouping_fields = (product, product_name, category_name)
        order_by = (category, )
        first_column = "Product"
        group_name = lambda i: "%s - %s" % (i[category_name], i[product_name])  # noqa

    # Group the responses per-field.
    for field in fields:
        concrete_field = AttendeeProfile._meta.get_field(field)
        field_verbose = concrete_field.verbose_name

        # Render the correct values for related fields
        if field in related_fields:
            # Get all of the IDs that will appear
            all_ids = profiles.order_by(field).values(field)
            all_ids = [i[field] for i in all_ids if i[field] is not None]
            # Get all of the concrete objects for those IDs
            model = concrete_field.related_model
            all_objects = model.objects.filter(id__in=all_ids)
            all_objects_by_id = dict((i.id, i) for i in all_objects)

            # Define a function to render those IDs.
            def display_field(value):
                if value in all_objects_by_id:
                    return all_objects_by_id[value]
                else:
                    return None
        else:
            def display_field(value):
                return value

        status_count = lambda status: Case(When(  # noqa
                attendee__user__cart__status=status,
                then=Value(1),
            ),
            default=Value(0),
            output_field=models.fields.IntegerField(),
        )
        paid_count = status_count(commerce.Cart.STATUS_PAID)
        unpaid_count = status_count(commerce.Cart.STATUS_ACTIVE)

        groups = profiles.order_by(
            *(order_by + (field, ))
        ).values(
            *(grouping_fields + (field, ))
        ).annotate(
            paid_count=Sum(paid_count),
            unpaid_count=Sum(unpaid_count),
        )
        output.append(ListReport(
            "Grouped by %s" % field_verbose,
            [first_column, field_verbose, "paid", "unpaid"],
            [
                (
                    group_name(group),
                    display_field(group[field]),
                    group["paid_count"] or 0,
                    group["unpaid_count"] or 0,
                )
                for group in groups
            ],
        ))

    # DO the report for individual attendees

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

    def display_field(profile, field):
        field_type = AttendeeProfile._meta.get_field(field)
        attr = getattr(profile, field)

        if isinstance(field_type, models.ManyToManyField):
            return [str(i) for i in attr.all()] or ""
        else:
            return attr

    headings = ["User ID", "Name", "Email", "Product", "Item Status"]
    headings.extend(field_names)
    data = []
    for item in items:
        profile = by_user[item.cart.user]
        line = [
            item.cart.user.id,
            getattr(profile, name_field),
            profile.attendee.user.email,
            item.product,
            status_display[item.cart.status],
        ] + [
            display_field(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
Lists attendees for a given product/category selection along with
    profile data.