Пример #1
0
    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()

        if self.copy_from:
            i = modelcopy(self.copy_from)
            i.pk = None
            kwargs['instance'] = i
        else:
            kwargs['instance'] = ItemCategory(event=self.request.event)
        return kwargs
Пример #2
0
def order_overview(
        event: Event, subevent: SubEvent=None, date_filter='', date_from=None, date_until=None, fees=False,
        admission_only=False
) -> Tuple[List[Tuple[ItemCategory, List[Item]]], Dict[str, Tuple[Decimal, Decimal]]]:
    items = event.items.all().select_related(
        'category',  # for re-grouping
    ).prefetch_related(
        'variations'
    ).order_by('category__position', 'category_id', 'position', 'name')

    qs = OrderPosition.all
    if subevent:
        qs = qs.filter(subevent=subevent)
    if admission_only:
        qs = qs.filter(item__admission=True)
        items = items.filter(admission=True)

    if date_from and isinstance(date_from, date):
        date_from = make_aware(datetime.combine(
            date_from,
            time(hour=0, minute=0, second=0, microsecond=0)
        ), event.timezone)

    if date_until and isinstance(date_until, date):
        date_until = make_aware(datetime.combine(
            date_until + timedelta(days=1),
            time(hour=0, minute=0, second=0, microsecond=0)
        ), event.timezone)

    if date_filter == 'order_date':
        if date_from:
            qs = qs.filter(order__datetime__gte=date_from)
        if date_until:
            qs = qs.filter(order__datetime__lt=date_until)
    elif date_filter == 'last_payment_date':
        p_date = OrderPayment.objects.filter(
            order=OuterRef('order'),
            state__in=[OrderPayment.PAYMENT_STATE_CONFIRMED, OrderPayment.PAYMENT_STATE_REFUNDED],
            payment_date__isnull=False
        ).values('order').annotate(
            m=Max('payment_date')
        ).values('m').order_by()
        qs = qs.annotate(payment_date=Subquery(p_date, output_field=DateTimeField()))
        if date_from:
            qs = qs.filter(payment_date__gte=date_from)
        if date_until:
            qs = qs.filter(payment_date__lt=date_until)

    counters = qs.filter(
        order__event=event
    ).annotate(
        status=Case(
            When(canceled=True, then=Value('c')),
            default=F('order__status')
        )
    ).values(
        'item', 'variation', 'status'
    ).annotate(cnt=Count('id'), price=Sum('price'), tax_value=Sum('tax_value')).order_by()

    states = {
        'canceled': Order.STATUS_CANCELED,
        'paid': Order.STATUS_PAID,
        'pending': Order.STATUS_PENDING,
        'expired': Order.STATUS_EXPIRED,
    }
    num = {}
    for l, s in states.items():
        num[l] = {
            (p['item'], p['variation']): (p['cnt'], p['price'], p['price'] - p['tax_value'])
            for p in counters if p['status'] == s
        }

    num['total'] = dictsum(num['pending'], num['paid'])

    for item in items:
        item.all_variations = list(item.variations.all())
        item.has_variations = (len(item.all_variations) > 0)
        item.num = {}
        if item.has_variations:
            for var in item.all_variations:
                variid = var.id
                var.num = {}
                for l in states.keys():
                    var.num[l] = num[l].get((item.id, variid), (0, 0, 0))
                var.num['total'] = num['total'].get((item.id, variid), (0, 0, 0))
            for l in states.keys():
                item.num[l] = tuplesum(var.num[l] for var in item.all_variations)
            item.num['total'] = tuplesum(var.num['total'] for var in item.all_variations)
        else:
            for l in states.keys():
                item.num[l] = num[l].get((item.id, None), (0, 0, 0))
            item.num['total'] = num['total'].get((item.id, None), (0, 0, 0))

    nonecat = ItemCategory(name=_('Uncategorized'))
    # Regroup those by category
    items_by_category = sorted(
        [
            # a group is a tuple of a category and a list of items
            (cat if cat is not None else nonecat, [i for i in items if i.category == cat])
            for cat in set([i.category for i in items])
            # insert categories into a set for uniqueness
            # a set is unsorted, so sort again by category
        ],
        key=lambda group: (group[0].position, group[0].id) if (
            group[0] is not None and group[0].id is not None) else (0, 0)
    )

    for c in items_by_category:
        c[0].num = {}
        for l in states.keys():
            c[0].num[l] = tuplesum(item.num[l] for item in c[1])
        c[0].num['total'] = tuplesum(item.num['total'] for item in c[1])

    # Payment fees
    payment_cat_obj = DummyObject()
    payment_cat_obj.name = _('Fees')
    payment_items = []

    if not subevent and fees:
        qs = OrderFee.all.filter(
            order__event=event
        ).annotate(
            status=Case(
                When(canceled=True, then=Value('c')),
                default=F('order__status')
            )
        )
        if date_filter == 'order_date':
            if date_from:
                qs = qs.filter(order__datetime__gte=date_from)
            if date_until:
                qs = qs.filter(order__datetime__lt=date_until)
        elif date_filter == 'last_payment_date':
            qs = qs.annotate(payment_date=Subquery(p_date, output_field=DateTimeField()))
            if date_from:
                qs = qs.filter(payment_date__gte=date_from)
            if date_until:
                qs = qs.filter(payment_date__lt=date_until)
        counters = qs.values(
            'fee_type', 'internal_type', 'status'
        ).annotate(cnt=Count('id'), value=Sum('value'), tax_value=Sum('tax_value')).order_by()

        for l, s in states.items():
            num[l] = {
                (o['fee_type'], o['internal_type']): (o['cnt'], o['value'], o['value'] - o['tax_value'])
                for o in counters if o['status'] == s
            }
        num['total'] = dictsum(num['pending'], num['paid'])

        provider_names = {
            k: v.verbose_name
            for k, v in event.get_payment_providers().items()
        }
        names = dict(OrderFee.FEE_TYPES)

        for pprov, total in sorted(num['total'].items(), key=lambda i: i[0]):
            ppobj = DummyObject()
            if pprov[0] == OrderFee.FEE_TYPE_PAYMENT:
                ppobj.name = '{} - {}'.format(names[pprov[0]], provider_names.get(pprov[1], pprov[1]))
            else:
                name = pprov[1]
                for r, resp in order_fee_type_name.send(sender=event, fee_type=pprov[0], internal_type=pprov[1]):
                    if resp:
                        name = resp
                        break

                ppobj.name = '{} - {}'.format(names[pprov[0]], name)
            ppobj.provider = pprov[1]
            ppobj.has_variations = False
            ppobj.num = {}
            for l in states.keys():
                ppobj.num[l] = num[l].get(pprov, (0, 0, 0))
            ppobj.num['total'] = total
            payment_items.append(ppobj)

        payment_cat_obj.num = {}
        for l in states.keys():
            payment_cat_obj.num[l] = (
                Dontsum(''), sum(i.num[l][1] for i in payment_items), sum(i.num[l][2] for i in payment_items)
            )
        payment_cat_obj.num['total'] = (
            Dontsum(''), sum(i.num['total'][1] for i in payment_items), sum(i.num['total'][2] for i in payment_items)
        )
        payment_cat = (payment_cat_obj, payment_items)
        any_payment = any(payment_cat_obj.num[s][1] for s in states.keys())
        if any_payment:
            items_by_category.append(payment_cat)

    total = {
        'num': {'total': tuplesum(c.num['total'] for c, i in items_by_category)}
    }
    for l in states.keys():
        total['num'][l] = tuplesum(c.num[l] for c, i in items_by_category)

    return items_by_category, total
Пример #3
0
def order_overview(event: Event) -> Tuple[List[Tuple[ItemCategory, List[Item]]], Dict[str, Tuple[Decimal, Decimal]]]:
    items = event.items.all().select_related(
        'category',  # for re-grouping
    ).order_by('category__position', 'category_id', 'name')

    num_total = {
        (p['item'], p['variation']): (p['cnt'], p['price'])
        for p in (OrderPosition.objects
                  .filter(order__event=event,
                          order__status__in=[Order.STATUS_PENDING, Order.STATUS_EXPIRED, Order.STATUS_PAID])
                  .values('item', 'variation')
                  .annotate(cnt=Count('id'), price=Sum('price')).order_by())
    }
    num_canceled = {
        (p['item'], p['variation']): (p['cnt'], p['price'])
        for p in (OrderPosition.objects
                  .filter(order__event=event, order__status=Order.STATUS_CANCELED)
                  .values('item', 'variation')
                  .annotate(cnt=Count('id'), price=Sum('price')).order_by())
    }
    num_refunded = {
        (p['item'], p['variation']): (p['cnt'], p['price'])
        for p in (OrderPosition.objects
                  .filter(order__event=event, order__status=Order.STATUS_REFUNDED)
                  .values('item', 'variation')
                  .annotate(cnt=Count('id'), price=Sum('price')).order_by())
    }
    num_pending = {
        (p['item'], p['variation']): (p['cnt'], p['price'])
        for p in (OrderPosition.objects
                  .filter(order__event=event,
                          order__status__in=(Order.STATUS_PENDING, Order.STATUS_EXPIRED))
                  .values('item', 'variation')
                  .annotate(cnt=Count('id'), price=Sum('price')).order_by())
    }
    num_paid = {
        (p['item'], p['variation']): (p['cnt'], p['price'])
        for p in (OrderPosition.objects
                  .filter(order__event=event, order__status=Order.STATUS_PAID)
                  .values('item', 'variation')
                  .annotate(cnt=Count('id'), price=Sum('price')).order_by())
    }

    for item in items:
        item.all_variations = list(item.variations.all())
        item.has_variations = (len(item.all_variations) > 0)
        if item.has_variations:
            for var in item.all_variations:
                variid = var.id
                var.num_total = num_total.get((item.id, variid), (0, 0))
                var.num_pending = num_pending.get((item.id, variid), (0, 0))
                var.num_canceled = num_canceled.get((item.id, variid), (0, 0))
                var.num_refunded = num_refunded.get((item.id, variid), (0, 0))
                var.num_paid = num_paid.get((item.id, variid), (0, 0))
            item.num_total = tuplesum(var.num_total for var in item.all_variations)
            item.num_pending = tuplesum(var.num_pending for var in item.all_variations)
            item.num_canceled = tuplesum(var.num_canceled for var in item.all_variations)
            item.num_refunded = tuplesum(var.num_refunded for var in item.all_variations)
            item.num_paid = tuplesum(var.num_paid for var in item.all_variations)
        else:
            item.num_total = num_total.get((item.id, None), (0, 0))
            item.num_pending = num_pending.get((item.id, None), (0, 0))
            item.num_canceled = num_canceled.get((item.id, None), (0, 0))
            item.num_refunded = num_refunded.get((item.id, None), (0, 0))
            item.num_paid = num_paid.get((item.id, None), (0, 0))

    nonecat = ItemCategory(name=_('Uncategorized'))
    # Regroup those by category
    items_by_category = sorted(
        [
            # a group is a tuple of a category and a list of items
            (cat if cat is not None else nonecat, [i for i in items if i.category == cat])
            for cat in set([i.category for i in items])
            # insert categories into a set for uniqueness
            # a set is unsorted, so sort again by category
        ],
        key=lambda group: (group[0].position, group[0].id) if (
            group[0] is not None and group[0].id is not None) else (0, 0)
    )

    for c in items_by_category:
        c[0].num_total = tuplesum(item.num_total for item in c[1])
        print(c[1], c[0].num_total, [item.num_total for item in c[1]])
        c[0].num_pending = tuplesum(item.num_pending for item in c[1])
        c[0].num_canceled = tuplesum(item.num_canceled for item in c[1])
        c[0].num_refunded = tuplesum(item.num_refunded for item in c[1])
        c[0].num_paid = tuplesum(item.num_paid for item in c[1])

    # Payment fees
    payment_cat_obj = DummyObject()
    payment_cat_obj.name = _('Payment method fees')
    payment_items = []
    num_total = {
        o['payment_provider']: (o['cnt'], o['payment_fee'])
        for o in (Order.objects
                  .filter(event=event)
                  .values('payment_provider')
                  .annotate(cnt=Count('id'), payment_fee=Sum('payment_fee')).order_by())
    }
    num_canceled = {
        o['payment_provider']: (o['cnt'], o['payment_fee'])
        for o in (Order.objects
                  .filter(event=event, status=Order.STATUS_CANCELED)
                  .values('payment_provider')
                  .annotate(cnt=Count('id'), payment_fee=Sum('payment_fee')).order_by())
    }
    num_refunded = {
        o['payment_provider']: (o['cnt'], o['payment_fee'])
        for o in (Order.objects
                  .filter(event=event, status=Order.STATUS_REFUNDED)
                  .values('payment_provider')
                  .annotate(cnt=Count('id'), payment_fee=Sum('payment_fee')).order_by())
    }
    num_pending = {
        o['payment_provider']: (o['cnt'], o['payment_fee'])
        for o in (Order.objects
                  .filter(event=event, status__in=(Order.STATUS_PENDING, Order.STATUS_EXPIRED))
                  .values('payment_provider')
                  .annotate(cnt=Count('id'), payment_fee=Sum('payment_fee')).order_by())
    }
    num_paid = {
        o['payment_provider']: (o['cnt'], o['payment_fee'])
        for o in (Order.objects
                  .filter(event=event, status=Order.STATUS_PAID)
                  .values('payment_provider')
                  .annotate(cnt=Count('id'), payment_fee=Sum('payment_fee')).order_by())
    }

    provider_names = {}
    responses = register_payment_providers.send(event)
    for receiver, response in responses:
        provider = response(event)
        provider_names[provider.identifier] = provider.verbose_name

    for pprov, total in num_total.items():
        ppobj = DummyObject()
        ppobj.name = provider_names.get(pprov, pprov)
        ppobj.provider = pprov
        ppobj.has_variations = False
        ppobj.num_total = total
        ppobj.num_canceled = num_canceled.get(pprov, (0, 0))
        ppobj.num_refunded = num_refunded.get(pprov, (0, 0))
        ppobj.num_pending = num_pending.get(pprov, (0, 0))
        ppobj.num_paid = num_paid.get(pprov, (0, 0))
        payment_items.append(ppobj)

    payment_cat_obj.num_total = (Dontsum(''), sum(i.num_total[1] for i in payment_items))
    payment_cat_obj.num_canceled = (Dontsum(''), sum(i.num_canceled[1] for i in payment_items))
    payment_cat_obj.num_refunded = (Dontsum(''), sum(i.num_refunded[1] for i in payment_items))
    payment_cat_obj.num_pending = (Dontsum(''), sum(i.num_pending[1] for i in payment_items))
    payment_cat_obj.num_paid = (Dontsum(''), sum(i.num_paid[1] for i in payment_items))
    payment_cat = (payment_cat_obj, payment_items)

    items_by_category.append(payment_cat)

    total = {
        'num_total': tuplesum(c.num_total for c, i in items_by_category),
        'num_pending': tuplesum(c.num_pending for c, i in items_by_category),
        'num_canceled': tuplesum(c.num_canceled for c, i in items_by_category),
        'num_refunded': tuplesum(c.num_refunded for c, i in items_by_category),
        'num_paid': tuplesum(c.num_paid for c, i in items_by_category)
    }

    return items_by_category, total
Пример #4
0
def order_overview(
    event: Event,
    subevent: SubEvent = None
) -> Tuple[List[Tuple[ItemCategory, List[Item]]], Dict[str, Tuple[Decimal,
                                                                  Decimal]]]:
    items = event.items.all().select_related(
        'category',  # for re-grouping
    ).prefetch_related('variations').order_by('category__position',
                                              'category_id', 'position',
                                              'name')

    qs = OrderPosition.objects
    if subevent:
        qs = qs.filter(subevent=subevent)
    counters = qs.filter(order__event=event).values(
        'item', 'variation',
        'order__status').annotate(cnt=Count('id'),
                                  price=Sum('price'),
                                  tax_value=Sum('tax_value')).order_by()

    num_canceled = {(p['item'], p['variation']):
                    (p['cnt'], p['price'], p['price'] - p['tax_value'])
                    for p in counters
                    if p['order__status'] == Order.STATUS_CANCELED}
    num_refunded = {(p['item'], p['variation']):
                    (p['cnt'], p['price'], p['price'] - p['tax_value'])
                    for p in counters
                    if p['order__status'] == Order.STATUS_REFUNDED}
    num_paid = {(p['item'], p['variation']):
                (p['cnt'], p['price'], p['price'] - p['tax_value'])
                for p in counters if p['order__status'] == Order.STATUS_PAID}
    num_pending = {(p['item'], p['variation']):
                   (p['cnt'], p['price'], p['price'] - p['tax_value'])
                   for p in counters
                   if p['order__status'] == Order.STATUS_PENDING}
    num_expired = {(p['item'], p['variation']):
                   (p['cnt'], p['price'], p['price'] - p['tax_value'])
                   for p in counters
                   if p['order__status'] == Order.STATUS_EXPIRED}
    num_total = dictsum(num_pending, num_paid)

    for item in items:
        item.all_variations = list(item.variations.all())
        item.has_variations = (len(item.all_variations) > 0)
        if item.has_variations:
            for var in item.all_variations:
                variid = var.id
                var.num_total = num_total.get((item.id, variid), (0, 0, 0))
                var.num_pending = num_pending.get((item.id, variid), (0, 0, 0))
                var.num_expired = num_expired.get((item.id, variid), (0, 0, 0))
                var.num_canceled = num_canceled.get((item.id, variid),
                                                    (0, 0, 0))
                var.num_refunded = num_refunded.get((item.id, variid),
                                                    (0, 0, 0))
                var.num_paid = num_paid.get((item.id, variid), (0, 0, 0))
            item.num_total = tuplesum(var.num_total
                                      for var in item.all_variations)
            item.num_pending = tuplesum(var.num_pending
                                        for var in item.all_variations)
            item.num_expired = tuplesum(var.num_expired
                                        for var in item.all_variations)
            item.num_canceled = tuplesum(var.num_canceled
                                         for var in item.all_variations)
            item.num_refunded = tuplesum(var.num_refunded
                                         for var in item.all_variations)
            item.num_paid = tuplesum(var.num_paid
                                     for var in item.all_variations)
        else:
            item.num_total = num_total.get((item.id, None), (0, 0, 0))
            item.num_pending = num_pending.get((item.id, None), (0, 0, 0))
            item.num_expired = num_expired.get((item.id, None), (0, 0, 0))
            item.num_canceled = num_canceled.get((item.id, None), (0, 0, 0))
            item.num_refunded = num_refunded.get((item.id, None), (0, 0, 0))
            item.num_paid = num_paid.get((item.id, None), (0, 0, 0))

    nonecat = ItemCategory(name=_('Uncategorized'))
    # Regroup those by category
    items_by_category = sorted(
        [
            # a group is a tuple of a category and a list of items
            (cat if cat is not None else nonecat,
             [i for i in items if i.category == cat])
            for cat in set([i.category for i in items])
            # insert categories into a set for uniqueness
            # a set is unsorted, so sort again by category
        ],
        key=lambda group: (group[0].position, group[0].id)
        if (group[0] is not None and group[0].id is not None) else (0, 0))

    for c in items_by_category:
        c[0].num_total = tuplesum(item.num_total for item in c[1])
        c[0].num_pending = tuplesum(item.num_pending for item in c[1])
        c[0].num_expired = tuplesum(item.num_expired for item in c[1])
        c[0].num_canceled = tuplesum(item.num_canceled for item in c[1])
        c[0].num_refunded = tuplesum(item.num_refunded for item in c[1])
        c[0].num_paid = tuplesum(item.num_paid for item in c[1])

    # Payment fees
    payment_cat_obj = DummyObject()
    payment_cat_obj.name = _('Fees')
    payment_items = []

    if not subevent:
        counters = OrderFee.objects.filter(order__event=event).values(
            'fee_type', 'internal_type',
            'order__status').annotate(cnt=Count('id'),
                                      value=Sum('value'),
                                      tax_value=Sum('tax_value')).order_by()

        num_canceled = {(o['fee_type'], o['internal_type']):
                        (o['cnt'], o['value'], o['value'] - o['tax_value'])
                        for o in counters
                        if o['order__status'] == Order.STATUS_CANCELED}
        num_refunded = {(o['fee_type'], o['internal_type']):
                        (o['cnt'], o['value'], o['value'] - o['tax_value'])
                        for o in counters
                        if o['order__status'] == Order.STATUS_REFUNDED}
        num_pending = {(o['fee_type'], o['internal_type']):
                       (o['cnt'], o['value'], o['value'] - o['tax_value'])
                       for o in counters
                       if o['order__status'] == Order.STATUS_PENDING}
        num_expired = {(o['fee_type'], o['internal_type']):
                       (o['cnt'], o['value'], o['value'] - o['tax_value'])
                       for o in counters
                       if o['order__status'] == Order.STATUS_EXPIRED}
        num_paid = {(o['fee_type'], o['internal_type']):
                    (o['cnt'], o['value'], o['value'] - o['tax_value'])
                    for o in counters
                    if o['order__status'] == Order.STATUS_PAID}
        num_total = dictsum(num_pending, num_paid)

        provider_names = {
            k: v.verbose_name
            for k, v in event.get_payment_providers().items()
        }
        names = dict(OrderFee.FEE_TYPES)

        for pprov, total in sorted(num_total.items(), key=lambda i: i[0]):
            ppobj = DummyObject()
            if pprov[0] == OrderFee.FEE_TYPE_PAYMENT:
                ppobj.name = '{} - {}'.format(
                    names[OrderFee.FEE_TYPE_PAYMENT],
                    provider_names.get(pprov[1], pprov[1]))
            else:
                ppobj.name = '{} - {}'.format(names[OrderFee.FEE_TYPE_PAYMENT],
                                              pprov[1])
            ppobj.provider = pprov[1]
            ppobj.has_variations = False
            ppobj.num_total = total
            ppobj.num_canceled = num_canceled.get(pprov, (0, 0, 0))
            ppobj.num_refunded = num_refunded.get(pprov, (0, 0, 0))
            ppobj.num_expired = num_expired.get(pprov, (0, 0, 0))
            ppobj.num_pending = num_pending.get(pprov, (0, 0, 0))
            ppobj.num_paid = num_paid.get(pprov, (0, 0, 0))
            payment_items.append(ppobj)

        payment_cat_obj.num_total = (Dontsum(''),
                                     sum(i.num_total[1]
                                         for i in payment_items),
                                     sum(i.num_total[2]
                                         for i in payment_items))
        payment_cat_obj.num_canceled = (Dontsum(''),
                                        sum(i.num_canceled[1]
                                            for i in payment_items),
                                        sum(i.num_canceled[2]
                                            for i in payment_items))
        payment_cat_obj.num_refunded = (Dontsum(''),
                                        sum(i.num_refunded[1]
                                            for i in payment_items),
                                        sum(i.num_refunded[2]
                                            for i in payment_items))
        payment_cat_obj.num_expired = (Dontsum(''),
                                       sum(i.num_expired[1]
                                           for i in payment_items),
                                       sum(i.num_expired[2]
                                           for i in payment_items))
        payment_cat_obj.num_pending = (Dontsum(''),
                                       sum(i.num_pending[1]
                                           for i in payment_items),
                                       sum(i.num_pending[2]
                                           for i in payment_items))
        payment_cat_obj.num_paid = (Dontsum(''),
                                    sum(i.num_paid[1] for i in payment_items),
                                    sum(i.num_paid[2] for i in payment_items))
        payment_cat = (payment_cat_obj, payment_items)

        items_by_category.append(payment_cat)

    total = {
        'num_total': tuplesum(c.num_total for c, i in items_by_category),
        'num_pending': tuplesum(c.num_pending for c, i in items_by_category),
        'num_expired': tuplesum(c.num_expired for c, i in items_by_category),
        'num_canceled': tuplesum(c.num_canceled for c, i in items_by_category),
        'num_refunded': tuplesum(c.num_refunded for c, i in items_by_category),
        'num_paid': tuplesum(c.num_paid for c, i in items_by_category)
    }

    return items_by_category, total