forked from CGM_Public/pretix_original
Compare commits
2 Commits
master
...
invoice-gr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcf15cbac1 | ||
|
|
b554fc1ad5 |
@@ -62,6 +62,63 @@ from pretix.presale.style import get_fonts
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def addon_aware_groupby(iterable, key, is_addon):
|
||||
"""
|
||||
We use groupby() to visually group identical lines on an invoice. For example, instead of
|
||||
|
||||
Product 1 5.00 EUR
|
||||
Product 1 5.00 EUR
|
||||
Product 1 5.00 EUR
|
||||
Product 2 7.00 EUR
|
||||
|
||||
We want to print
|
||||
|
||||
3x Product 1 5.00 EUR = 15.00 EUR
|
||||
Product 2 7.00 EUR
|
||||
|
||||
However, this fails for setups with addon-products since groupby() only groups consecutive
|
||||
lines with the same identity. So in
|
||||
|
||||
Product 1 5.00 EUR
|
||||
+ Addon 1 2.00 EUR
|
||||
Product 1 5.00 EUR
|
||||
+ Addon 1 2.00 EUR
|
||||
Product 1 5.00 EUR
|
||||
+ Addon 2 3.00 EUR
|
||||
|
||||
There is no consecutive repetition of the same entity. This function provides a specialised groupby which
|
||||
understands the product/addon relationship and packs groups of these addons together if they are, in fact,
|
||||
identical groups:
|
||||
|
||||
2x Product 1 5.00 EUR = 10.00 EUR
|
||||
+ 2x Addon 1 2.00 EUR = 4.00 EUR
|
||||
Product 1 5.00 EUR
|
||||
+ Addon 2 3.00 EUR
|
||||
"""
|
||||
packed_groups = []
|
||||
|
||||
for i in iterable:
|
||||
if is_addon(i):
|
||||
packed_groups[-1][1].append(i)
|
||||
else:
|
||||
packed_groups.append((i, []))
|
||||
# Each packed_groups element contains (parent product, list of addon products)
|
||||
|
||||
def _reorder(packed_groups):
|
||||
# Emit the products as individual products again, reordered by "all parent products, then all addon products"
|
||||
# within each group.
|
||||
for group_grouper, grouped in groupby(packed_groups, key=lambda g: key(g[0]) + tuple(key(a) for a in g[1])):
|
||||
grouped = list(grouped)
|
||||
for grp in grouped:
|
||||
yield grp[0]
|
||||
for i in range(max(len(grp[1]) for grp in grouped)):
|
||||
for grp in grouped:
|
||||
if len(grp[1]) > i:
|
||||
yield grp[1][i]
|
||||
|
||||
return groupby(_reorder(packed_groups), key)
|
||||
|
||||
|
||||
class NumberedCanvas(Canvas):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.font_regular = kwargs.pop('font_regular')
|
||||
@@ -635,7 +692,11 @@ class ClassicInvoiceRenderer(BaseReportlabInvoiceRenderer):
|
||||
line.event_date_from, line.event_date_to)
|
||||
|
||||
total = Decimal('0.00')
|
||||
for (description, tax_rate, tax_name, net_value, gross_value, *ignored), lines in groupby(self.invoice.lines.all(), key=_group_key):
|
||||
for (description, tax_rate, tax_name, net_value, gross_value, *ignored), lines in addon_aware_groupby(
|
||||
self.invoice.lines.all(),
|
||||
key=_group_key,
|
||||
is_addon=lambda l: l.description.startswith(" +"),
|
||||
):
|
||||
lines = list(lines)
|
||||
if has_taxes:
|
||||
if len(lines) > 1:
|
||||
|
||||
@@ -38,10 +38,12 @@ from decimal import Decimal
|
||||
|
||||
import pytest
|
||||
from django.db import DatabaseError, transaction
|
||||
from django.utils.itercompat import is_iterable
|
||||
from django.utils.timezone import now
|
||||
from django_countries.fields import Country
|
||||
from django_scopes import scope, scopes_disabled
|
||||
|
||||
from pretix.base.invoice import addon_aware_groupby
|
||||
from pretix.base.models import (
|
||||
Event, ExchangeRate, Invoice, InvoiceAddress, Item, ItemVariation, Order,
|
||||
OrderPosition, Organizer,
|
||||
@@ -606,3 +608,55 @@ def test_sales_channels_qualify(env):
|
||||
|
||||
event.settings.set('invoice_generate_sales_channels', [])
|
||||
assert invoice_qualified(order) is False
|
||||
|
||||
|
||||
def test_addon_aware_groupby():
|
||||
def is_addon(item):
|
||||
is_addon, id, price = item
|
||||
return is_addon
|
||||
|
||||
def key(item):
|
||||
return item
|
||||
|
||||
def listify(it):
|
||||
return [listify(i) if is_iterable(i) else i for i in it]
|
||||
|
||||
assert listify(addon_aware_groupby([
|
||||
(False, 1, 5.00),
|
||||
(False, 1, 5.00),
|
||||
(False, 1, 5.00),
|
||||
(False, 2, 7.00),
|
||||
], key, is_addon)) == [
|
||||
[[False, 1, 5.00], [
|
||||
[False, 1, 5.00],
|
||||
[False, 1, 5.00],
|
||||
[False, 1, 5.00],
|
||||
]],
|
||||
[[False, 2, 7.00], [
|
||||
[False, 2, 7.00],
|
||||
]],
|
||||
]
|
||||
|
||||
assert listify(addon_aware_groupby([
|
||||
(False, 1, 5.00),
|
||||
(True, 101, 2.00),
|
||||
(False, 1, 5.00),
|
||||
(True, 101, 2.00),
|
||||
(False, 1, 5.00),
|
||||
(True, 102, 3.00),
|
||||
], key, is_addon)) == [
|
||||
[[False, 1, 5.00], [
|
||||
[False, 1, 5.00],
|
||||
[False, 1, 5.00],
|
||||
]],
|
||||
[[True, 101, 2.00], [
|
||||
[True, 101, 2.00],
|
||||
[True, 101, 2.00],
|
||||
]],
|
||||
[[False, 1, 5.00], [
|
||||
[False, 1, 5.00],
|
||||
]],
|
||||
[[True, 102, 3.00], [
|
||||
[True, 102, 3.00],
|
||||
]],
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user