Invoicing: Allow types to add text and watermarks (#5453)

This commit is contained in:
Raphael Michel
2025-09-22 10:04:25 +02:00
committed by GitHub
parent a7cbcb29b5
commit 08961091f6
4 changed files with 62 additions and 2 deletions

View File

@@ -22,7 +22,7 @@
from django import forms
from django.core.validators import RegexValidator
from django.utils.translation import pgettext_lazy
from django.utils.translation import pgettext, pgettext_lazy
from django_countries.fields import Country
from localflavor.it.forms import ITSocialSecurityNumberField
@@ -73,3 +73,12 @@ class ItalianSdITransmissionType(TransmissionType):
if is_business:
return base | {"company", "vat_id", "transmission_it_sdi_pec", "transmission_it_sdi_recipient_code"}
return base | {"transmission_it_sdi_codice_fiscale"}
def pdf_info_text(self) -> str:
# Watermark is not necessary as this is a usual precaution in Italy
return pgettext(
"italian_invoice",
"This PDF document is a visual copy of the invoice and does not constitute an invoice for VAT "
"purposes. The invoice is issued in XML format, transmitted in accordance with the procedures and terms "
"set forth in No. 89757/2018 of April 30, 2018, issued by the Director of the Revenue Agency."
)

View File

@@ -20,6 +20,7 @@
# <https://www.gnu.org/licenses/>.
#
import logging
import math
import re
import unicodedata
from collections import defaultdict
@@ -223,6 +224,9 @@ class BaseReportlabInvoiceRenderer(BaseInvoiceRenderer):
stylesheet.add(ParagraphStyle(name='FineprintHeading', fontName=self.font_bold, fontSize=8, leading=12))
stylesheet.add(ParagraphStyle(name='Fineprint', fontName=self.font_regular, fontSize=8, leading=10))
stylesheet.add(ParagraphStyle(name='FineprintRight', fontName=self.font_regular, fontSize=8, leading=10, alignment=TA_RIGHT))
stylesheet.add(ParagraphStyle(name='WarningBlock', fontName=self.font_bold, fontSize=10, leading=12,
alignment=TA_LEFT, borderWidth=1 * mm, borderColor=colors.black,
borderPadding=2 * mm, spaceBefore=5 * mm, spaceAfter=5 * mm))
return stylesheet
def _register_fonts(self):
@@ -576,11 +580,28 @@ class ClassicInvoiceRenderer(BaseReportlabInvoiceRenderer):
canvas.drawRightString(self.pagesize[0] - 20 * mm, (297 - 100) * mm, self._normalize(gettext('TEST MODE')))
canvas.restoreState()
def _draw_watermark(self, canvas):
watermark = self.invoice.transmission_type_instance.pdf_watermark()
if watermark:
canvas.saveState()
for font_size in range(200, 20, -10):
width = stringWidth(watermark, self.font_bold, font_size)
if width < self.pagesize[0]:
break
canvas.translate(self.pagesize[0] / 2, self.pagesize[1] / 2)
canvas.rotate(math.atan(self.pagesize[1] / self.pagesize[0]) / math.pi * 180)
canvas.setFont(self.font_bold, font_size)
canvas.setFillColorRGB(.92, .92, .92)
canvas.drawCentredString(0, - font_size / 2, self._normalize(watermark))
canvas.restoreState()
def _on_first_page(self, canvas: Canvas, doc):
canvas.setCreator('pretix.eu')
canvas.setTitle(pgettext('invoice', 'Invoice {num}').format(num=self.invoice.number))
canvas.saveState()
self._draw_watermark(canvas)
self._draw_footer(canvas)
self._draw_testmode(canvas)
self._draw_invoice_from_label(canvas)
@@ -610,6 +631,14 @@ class ClassicInvoiceRenderer(BaseReportlabInvoiceRenderer):
def _get_intro(self):
story = []
type_info_text = self.invoice.transmission_type_instance.pdf_info_text()
if type_info_text:
story.append(FontFallbackParagraph(
type_info_text,
self.stylesheet['WarningBlock']
))
if self.invoice.custom_field:
story.append(FontFallbackParagraph(
'{}: {}'.format(

View File

@@ -23,7 +23,7 @@ import re
from django import forms
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from django.utils.translation import gettext_lazy as _, pgettext
from django_countries.fields import Country
from pretix.base.invoicing.transmission import (
@@ -165,3 +165,13 @@ class PeppolTransmissionType(TransmissionType):
"company", "street", "zipcode", "city", "country",
}
return base | {"transmission_peppol_participant_id"}
def pdf_watermark(self) -> str:
return pgettext("peppol_invoice", "Visual copy")
def pdf_info_text(self) -> str:
return pgettext(
"peppol_invoice",
"This PDF document is a visual copy of the invoice and does not constitute an invoice for VAT "
"purposes. The original invoice is issued in XML format and transmitted through the Peppol network."
)

View File

@@ -104,6 +104,18 @@ class TransmissionType:
def transmission_info_to_form_data(self, transmission_info: dict) -> dict:
return transmission_info
def pdf_watermark(self) -> Optional[str]:
"""
Return a watermark that should be rendered across the PDF file.
"""
return None
def pdf_info_text(self) -> Optional[str]:
"""
Return an info text that should be rendered on the PDF file.
"""
return None
class TransmissionProvider:
"""