Group identical lines on invoice PDF (#2918)

This commit is contained in:
Raphael Michel
2022-11-21 15:47:57 +01:00
committed by GitHub
parent 50e79b51de
commit 5ee62c551e
2 changed files with 41 additions and 22 deletions

View File

@@ -23,6 +23,7 @@ import logging
from collections import defaultdict from collections import defaultdict
from decimal import Decimal from decimal import Decimal
from io import BytesIO from io import BytesIO
from itertools import groupby
from typing import Tuple from typing import Tuple
import bleach import bleach
@@ -554,31 +555,47 @@ class ClassicInvoiceRenderer(BaseReportlabInvoiceRenderer):
pgettext('invoice', 'Amount'), pgettext('invoice', 'Amount'),
)] )]
def _group_key(line):
return (line.description, line.tax_rate, line.tax_name, line.net_value, line.gross_value, line.subevent_id,
line.event_date_from, line.event_date_to)
total = Decimal('0.00') total = Decimal('0.00')
for line in self.invoice.lines.all(): for (description, tax_rate, tax_name, net_value, gross_value, *ignored), lines in groupby(self.invoice.lines.all(), key=_group_key):
lines = list(lines)
if has_taxes: if has_taxes:
if len(lines) > 1:
single_price_line = pgettext('invoice', 'Single price: {net_price} net / {gross_price} gross').format(
net_price=money_filter(net_value, self.invoice.event.currency),
gross_price=money_filter(gross_value, self.invoice.event.currency),
)
description = description + "\n" + single_price_line
tdata.append(( tdata.append((
Paragraph( Paragraph(
bleach.clean(line.description, tags=['br']).strip().replace('<br>', '<br/>').replace('\n', '<br />\n'), bleach.clean(description, tags=['br']).strip().replace('<br>', '<br/>').replace('\n', '<br />\n'),
self.stylesheet['Normal'] self.stylesheet['Normal']
), ),
"1", str(len(lines)),
localize(line.tax_rate) + " %", localize(tax_rate) + " %",
money_filter(line.net_value, self.invoice.event.currency), money_filter(net_value * len(lines), self.invoice.event.currency),
money_filter(line.gross_value, self.invoice.event.currency), money_filter(gross_value * len(lines), self.invoice.event.currency),
)) ))
else: else:
if len(lines) > 1:
single_price_line = pgettext('invoice', 'Single price: {price}').format(
price=money_filter(gross_value, self.invoice.event.currency),
)
description = description + "\n" + single_price_line
tdata.append(( tdata.append((
Paragraph( Paragraph(
bleach.clean(line.description, tags=['br']).strip().replace('<br>', '<br/>').replace('\n', '<br />\n'), bleach.clean(description, tags=['br']).strip().replace('<br>', '<br/>').replace('\n', '<br />\n'),
self.stylesheet['Normal'] self.stylesheet['Normal']
), ),
"1", str(len(lines)),
money_filter(line.gross_value, self.invoice.event.currency), money_filter(gross_value * len(lines), self.invoice.event.currency),
)) ))
taxvalue_map[line.tax_rate, line.tax_name] += line.tax_value taxvalue_map[tax_rate, tax_name] += (gross_value - net_value) * len(lines)
grossvalue_map[line.tax_rate, line.tax_name] += line.gross_value grossvalue_map[tax_rate, tax_name] += gross_value * len(lines)
total += line.gross_value total += gross_value * len(lines)
if has_taxes: if has_taxes:
tdata.append([ tdata.append([

View File

@@ -452,17 +452,19 @@ def build_preview_invoice_pdf(event):
if event.tax_rules.exists(): if event.tax_rules.exists():
for i, tr in enumerate(event.tax_rules.all()): for i, tr in enumerate(event.tax_rules.all()):
tax = tr.tax(Decimal('100.00'), base_price_is='gross') for j in range(150):
InvoiceLine.objects.create( tax = tr.tax(Decimal('100.00'), base_price_is='gross')
invoice=invoice, description=_("Sample product {}").format(i + 1), InvoiceLine.objects.create(
gross_value=tax.gross, tax_value=tax.tax, invoice=invoice, description=_("Sample product {}").format(i + 1),
tax_rate=tax.rate gross_value=tax.gross, tax_value=tax.tax,
) tax_rate=tax.rate
)
else: else:
InvoiceLine.objects.create( for i in range(150):
invoice=invoice, description=_("Sample product A"), InvoiceLine.objects.create(
gross_value=100, tax_value=0, tax_rate=0 invoice=invoice, description=_("Sample product A"),
) gross_value=100, tax_value=0, tax_rate=0
)
return event.invoice_renderer.generate(invoice) return event.invoice_renderer.generate(invoice)