# -*- coding: utf-8 -*- import os.path from reportlab.lib.pagesizes import A4 from reportlab.lib.units import cm, inch from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont, TTFError from reportlab.pdfgen import canvas from .InvoiceObjects import InvoiceTable, InvoiceText, InvoiceImage, GUTSCHRIFT from . import _formatPrice def find_font_file(filename): for n in range(4): candidate = os.path.abspath(os.path.join(os.path.dirname(__file__), '../' * n, 'ressource/fonts', filename)) if os.path.exists(candidate): return candidate def _registerFonts(): fonts = [ ("DejaVu", "DejaVuSans.ttf"), ("DejaVu-Bold", "DejaVuSans-Bold.ttf"), ("DejaVu-Italic", "DejaVuSans-Oblique.ttf"), ("DejaVu-BoldItalic", "DejaVuSans-BoldOblique.ttf") ] for fontname, fontfile in fonts: found = False try: pdfmetrics.registerFont(TTFont(fontname, fontfile)) found = True except TTFError: pass if not found: f = find_font_file(fontfile) if f: pdfmetrics.registerFont(TTFont(fontname, f)) class PDF(object): # Set default font size default_font_size = 8 font = 'DejaVu' # set margins topmargin = 2 * cm bottommargin = 2.2 * cm leftmargin = 2 * cm rightmargin = 2 * cm rightcolumn = 13 * cm canvas = None num_pages = 1 font_height = 0.3 * cm line_padding = 0.1 * cm line_height = font_height + 0.1 * cm invoice = None def __init__(self, invoice): _registerFonts() from io import BytesIO self.fd = BytesIO() self.canvas = canvas.Canvas(self.fd, pagesize=A4) self.invoice = invoice self.topcontent = -self.topmargin self.leftcontent = self.leftmargin self.rightcontent = A4[0] - self.rightmargin self.bottomcontent = -(A4[1] - self.bottommargin) self.font_size = 8 self.x = 2.0 * cm self.y = -4.8 * cm - self.font_size - 1 self.canvas.setFont(self.font, self.font_size) def _splitToWidth(self, text, width, font, size): '''_splitToWidth(canvas, text, width, font, size) Split a string to several lines of a given width.''' lines = [] paras = text.split('\n') for para in paras: words = para.split(' ') while len(words) > 0: mywords = [words[0], ] del words[0] while len(words) > 0 and self.canvas.stringWidth(' '.join(mywords) + ' ' + words[0], font, size) <= width: mywords.append(words[0]) del words[0] lines.append(' '.join(mywords)) return lines def _PageMarkers(self): """Setzt Falzmarken""" self.canvas.setStrokeColor((0, 0, 0)) self.canvas.setLineWidth(0.01 * cm) self.canvas.lines([(0.3 * cm, -10.5 * cm, 0.65 * cm, -10.5 * cm), (0.3 * cm, -21.0 * cm, 0.65 * cm, -21.0 * cm), (0.3 * cm, -14.85 * cm, 0.7 * cm, -14.85 * cm)]) def _lineHeight(self, fontsize=None, font=None): if not fontsize: fontsize = self.default_font_size if not font: font = self.font face = pdfmetrics.getFont(font).face string_height = (face.ascent - face.descent) / 1000 * fontsize return string_height + 0.1 * cm def _partHeight(self, part): height = 0 if isinstance(part, InvoiceText): left, right = self.leftcontent, self.rightcontent if part.urgent: left += 1.5 * cm right -= 1.5 * cm height += len(part.paragraphs) * 3 * self.line_padding # Rechne eine Zeile mehr für den Rahmen height += self.line_height if part.headline: height += (len(self._splitToWidth(part.headline, right - left, self.font + '-Bold', self.default_font_size + 1)) * self.line_height) + self.line_padding for para in part.paragraphs: height += (len(self._splitToWidth(para, right - left, self.font, self.default_font_size)) * self.line_height) + self.line_padding elif isinstance(part, InvoiceTable): # Eine Zeile plus 2 mal line_padding für Tabellenkopf height = self.line_height + 2 * self.line_padding # Wenn nur ein Element (plus Summen) hin passt, reicht uns das el = part.entries[0] # Die Abstände oben und unten height += 2 * self.line_padding # Die Breite ist konservativ if el['type'] == 'title': height += self.line_height + 0.2 * cm else: height += self.line_height * len(self._splitToWidth(el['subject'], 9.3 * cm, self.font, self.font_size)) if 'desc' in el and el['desc'] != '': height += self.line_height * len(self._splitToWidth(el['desc'], 11 * cm, self.font, self.font_size)) if part.vatType == 'net': # Eine Zeile mehr height += self.line_height + self.line_padding # Für die MwSt-Summen height += (self.line_height + self.line_padding) * len(part.vat) # Für den Rechnungsbetrag height += self.line_height + self.line_padding return height def _tableHead(self, part): self.canvas.setFont(self.font, self.font_size) self.canvas.drawString(self.leftcontent + (0.1 * cm), self.y - self.line_height + self.line_padding, 'Anz.') self.canvas.drawString(self.leftcontent + (2.1 * cm), self.y - self.line_height + self.line_padding, 'Beschreibung') if len(part.vat) == 1: self.canvas.drawRightString(self.leftcontent + (14.3 * cm), self.y - self.line_height + self.line_padding, 'Einzelpreis') else: self.canvas.drawRightString(self.leftcontent + (13.3 * cm), self.y - self.line_height + self.line_padding, 'Einzelpreis') self.canvas.drawRightString(self.leftcontent + (16.8 * cm), self.y - self.line_height + self.line_padding, 'Gesamtpreis') self.canvas.setLineWidth(0.01 * cm) self.canvas.line(self.leftcontent, self.y - self.line_height, self.rightcontent, self.y - self.line_height) self.y -= self.line_height + 0.02 * cm def _PageWrap(self): '''Seitenumbruch''' self.num_pages += 1 self.canvas.setFont(self.font, self.default_font_size - 2) self.canvas.drawRightString(self.rightcontent, self.bottomcontent + self.line_padding, 'Fortsetzung auf Seite %i' % self.num_pages) self.canvas.showPage() self.basicPage() self.y = self.topcontent - self.font_size self.canvas.setFillColor((0, 0, 0)) self.canvas.setFont(self.font, self.font_size - 2) self.canvas.drawCentredString(self.leftcontent + (self.rightcontent - self.leftcontent) / 2, self.y, '- Seite %i -' % self.num_pages) def _Footer(self): self.canvas.setStrokeColor((0, 0, 0)) self.canvas.setFillColor((0, 0, 0)) self.canvas.line(self.leftcontent, self.bottomcontent, self.rightcontent, self.bottomcontent) self.canvas.setFont(self.font, 7) lines = list(filter(None, [ self.invoice.seller['trade_name'], self.invoice.seller['name'] if self.invoice.seller['trade_name'] else None, self.invoice.seller['website'], self.invoice.seller['email'], ])) c = 0 for line in lines: c += 10 self.canvas.drawString(self.leftcontent, self.bottomcontent - c, line) if self.invoice.seller_vat_id: lines = list(filter(None, [ "USt-ID: " + self.invoice.seller_vat_id ])) c = 0 for line in lines: c += 10 self.canvas.drawString(self.leftcontent + ((self.rightcontent - self.leftcontent) // 3), self.bottomcontent - c, line) if not self.invoice.debit: iban = self.invoice.seller_bank_data['iban'] iban = ' '.join([iban[i:i + 4] for i in range(0, len(iban), 4)]) lines = [ f"IBAN: {iban}", self.invoice.seller_bank_data['bankname'], f"BIC: {self.invoice.seller_bank_data['bic']}" if self.invoice.seller_bank_data['bic'] else None, ] c = 0 for line in lines: c += 10 self.canvas.drawString(self.leftcontent + ((self.rightcontent - self.leftcontent) // 3) * 2, self.bottomcontent - c, line) def basicPage(self): # Set marker to top. self.canvas.translate(0, A4[1]) self._PageMarkers() self._Footer() def addressBox(self): lines = [ self.invoice.seller['trade_name'], self.invoice.seller['address']['line1'], self.invoice.seller['address']['line2'], self.invoice.seller['address']['line3'], self.invoice.seller['address']['postcode'] + ' ' + self.invoice.seller['address']['city_name'], ] address = ' · '.join(filter(None, lines)) self.canvas.drawString(self.x, self.y + 0.1 * cm, f' {address}') self.canvas.line(self.x, self.y, self.x + (8.5 * cm), self.y) self.y = self.y - self.font_size - 3 font_size = 11 x = self.x + 0.5 * cm self.y -= 0.5 * cm self.canvas.setFont(self.font, font_size) addresslines = filter(None, [ self.invoice.customer['name'].strip(), self.invoice.customer['address']['line1'] or '', self.invoice.customer['address']['line2'] or '', self.invoice.customer['address']['line3'] or '', ((self.invoice.customer['address']['postcode'] or '') + ' ' + ( self.invoice.customer['address']['city_name'] or '')).strip(), ]) for line in addresslines: self.canvas.drawString(x, self.y, line) self.y -= font_size * 0.03527 * cm * 1.2 def firstPage(self): self.basicPage() self.addressBox() self.y = self.topcontent self.canvas.drawImage(self.invoice.logo_image_file, self.rightcolumn, self.topcontent - (2 * cm), height=2 * cm, preserveAspectRatio=True, anchor='nw') self.y -= (2.5 * cm) self.canvas.setFont(self.font + "-Bold", self.font_size) self.canvas.drawString(self.rightcolumn, self.y, self.invoice.seller['trade_name'] or self.invoice.seller['name']) self.y -= (self.font_size + 5) self.canvas.setFont(self.font, self.font_size) lines = [ self.invoice.seller['name'] if self.invoice.seller['trade_name'] else None, self.invoice.seller['address']['line1'], self.invoice.seller['address']['line2'], self.invoice.seller['address']['line3'], self.invoice.seller['address']['postcode'] + ' ' + self.invoice.seller['address']['city_name'], self.invoice.seller['website'], ] address = filter(None, lines) for line in address: self.canvas.drawString(self.rightcolumn, self.y, line) self.y -= (self.font_size + 5) self.y -= 5 if self.invoice.seller['phone']: self.canvas.drawString(self.rightcolumn, self.y, f"Tel: {self.invoice.seller['phone']}") self.y -= (self.font_size + 5) if self.invoice.seller['email']: self.canvas.drawString(self.rightcolumn, self.y, f"E-Mail: {self.invoice.seller['email']}") self.y -= (self.font_size + 10) self.y = -9.5 * cm def title(self, title): self.canvas.setTitle(title) self.canvas.drawString(self.leftcontent, self.y, title) def renderRechnung(self): self.firstPage() self.canvas.setFont(self.font + '-Bold', self.font_size + 3) self.title(self.invoice.title) if self.invoice.tender: self.canvas.setFont(self.font, self.font_size) self.canvas.drawString(self.rightcolumn, self.y, "Erstellungsdatum:") self.canvas.drawRightString(self.rightcontent, self.y, "%s" % self.invoice.date.strftime('%d. %m. %Y')) self.y -= (self.font_size + 0.1 * cm) else: self.canvas.setFont(self.font + '-Bold', self.font_size) self.canvas.drawString(self.rightcolumn, self.y, "Bei Fragen bitte immer angeben:") self.y -= (self.font_size + 0.2 * cm) self.canvas.setFont(self.font, self.font_size) self.canvas.drawString(self.rightcolumn, self.y, "Rechnungsdatum:") self.canvas.drawRightString(self.rightcontent, self.y, "%s" % self.invoice.date.strftime('%d. %m. %Y')) self.y -= (self.font_size + 0.1 * cm) self.canvas.drawString(self.rightcolumn, self.y, "Rechnungsnummer:") self.canvas.drawRightString(self.rightcontent, self.y, "%s" % self.invoice.id) self.y -= (self.font_size + 0.1 * cm) if self.invoice.customerno: self.canvas.drawString(self.rightcolumn, self.y, "Kundennummer:") self.canvas.drawRightString(self.rightcontent, self.y, "%s" % self.invoice.customerno) self.y -= (self.font_size + 0.5 * cm) if self.invoice.leitweg_id: self.canvas.drawString(self.rightcolumn, self.y, "Leitweg-ID:") self.canvas.drawRightString(self.rightcontent, self.y, "%s" % self.invoice.leitweg_id) self.y -= (self.font_size + 0.1 * cm) if self.invoice.buyer_reference: self.canvas.drawString(self.rightcolumn, self.y, "Kunden-Referenz:") self.canvas.drawRightString(self.rightcontent, self.y, "%s" % self.invoice.buyer_reference) self.y -= (self.font_size + 0.1 * cm) if self.invoice.contract_number: self.canvas.drawString(self.rightcolumn, self.y, "Vertragsnummer:") self.canvas.drawRightString(self.rightcontent, self.y, "%s" % self.invoice.contract_number) self.y -= (self.font_size + 0.1 * cm) if self.invoice.order_number: self.canvas.drawString(self.rightcolumn, self.y, "Ihre Bestellnummer:") self.canvas.drawRightString(self.rightcontent, self.y, "%s" % self.invoice.order_number) self.y -= (self.font_size + 0.1 * cm) self.canvas.setFont(self.font, self.font_size) if self.invoice.salutation: self.canvas.drawString(self.leftcontent, self.y, self.invoice.salutation) self.y -= self.font_size + 0.2 * cm introText = 'hiermit stellen wir Ihnen die nachfolgend genannten Leistungen in Rechnung.' if self.invoice.tender: introText = 'hiermit unterbreiten wir Ihnen folgendes Angebot.' if self.invoice.type == GUTSCHRIFT: introText = 'nach unserer Berechnung entsteht für Sie folgende Gutschrift.' intro = self._splitToWidth(introText, self.rightcontent - self.leftcontent, self.font, self.font_size) for line in intro: self.canvas.drawString(self.leftcontent, self.y, line) self.y -= self.font_size + 0.1 * cm self.y -= self.font_size + 0.1 * cm font_size = self.default_font_size for part in self.invoice.parts: if self.y - self._partHeight(part) < (self.bottomcontent + (0.5 * cm)): self._PageWrap() self.y = self.topcontent - self.font_size - self.line_padding * 3 if isinstance(part, InvoiceTable): left = self.leftcontent right = self.rightcontent self._tableHead(part) temp_sum = 0.0 odd = True for el in part.entries: if el['type'] == 'title': self.y -= self.line_padding + 0.2 * cm self.canvas.setFillColorRGB(0, 0, 0) self.canvas.setFont(self.font + '-Italic', font_size) self.canvas.drawString(left, self.y - self.font_height, el['title']) self.canvas.setFont(self.font, font_size) self.y -= self.line_height + self.line_padding else: if len(part.vat) == 1: subject = self._splitToWidth(el['subject'], 9.8 * cm, self.font, font_size) else: subject = self._splitToWidth(el['subject'], 8.8 * cm, self.font, font_size) desc = [] if 'desc' in el and el['desc'] != '': desc = self._splitToWidth(el['desc'], 14.0 * cm, self.font, font_size) if 'period_start' in el and el['period_start']: if 'period_end' in el and el['period_end']: desc.extend(self._splitToWidth('Leistungszeitraum: %s - %s' % (el['period_start'].strftime('%d.%m.%Y'), el['period_end'].strftime('%d.%m.%Y')), 14.0 * cm, self.font, font_size)) else: desc.extend(self._splitToWidth('Leistungsdatum: %s' % (el['period_start'].strftime('%d.%m.%Y'),), 14.0 * cm, self.font, font_size)) need_lines = len(subject) + len(desc) # need page wrap? if self.y - (need_lines + 1 * (self.line_height + self.line_padding)) < ( self.bottomcontent + 1 * cm): self.canvas.setFont(self.font + '-Italic', font_size) # Zwischensumme self.canvas.drawRightString(left + 14.5 * cm, self.y - self.font_height, 'Zwischensumme:') self.canvas.drawRightString(left + 16.8 * cm, self.y - self.font_height, _formatPrice(temp_sum)) # page wrap self._PageWrap() self.y = self.topcontent - font_size - self.line_padding * 3 # header self._tableHead(part) self.y -= self.line_padding * 3 odd = True # übertrag self.canvas.setFont(self.font + '-Italic', font_size) self.canvas.drawRightString(left + 14.5 * cm, self.y - self.font_height, 'Übertrag:') self.canvas.drawRightString(left + 16.8 * cm, self.y - self.font_height, _formatPrice(temp_sum)) self.y -= self.font_height + self.line_padding * 3 self.canvas.setFont(self.font, self.default_font_size) # Zwischensumme (inkl. aktueller Posten) temp_sum += el['total'] # draw the background if not odd: self.canvas.setFillColorRGB(0.9, 0.9, 0.9) else: self.canvas.setFillColorRGB(1, 1, 1) self.canvas.rect(left, self.y - (need_lines * self.line_height) - (2 * self.line_padding), height=(need_lines * self.line_height) + (2 * self.line_padding), width=right - left, fill=1, stroke=0) self.canvas.setFillColorRGB(0, 0, 0) self.y -= self.line_padding self.canvas.drawRightString(left + 1.1 * cm, self.y - self.font_height, '%.0f' % el['count']) if el['unit']: self.canvas.drawString(left + 1.2 * cm, self.y - self.font_height, el['unit']) self.canvas.drawString(left + 2.2 * cm, self.y - self.font_height, subject[0]) if len(part.vat) == 1: self.canvas.drawRightString(left + 14.3 * cm, self.y - self.font_height, _formatPrice(el['price'])) else: self.canvas.drawRightString(left + 13.3 * cm, self.y - self.font_height, _formatPrice(el['price'])) self.canvas.drawString(left + 13.7 * cm, self.y - self.font_height, str(part.vat[el['vat']][1])) if el['tender']: self.canvas.drawRightString(left + 16.8 * cm, self.y - self.font_height, 'eventual') else: self.canvas.drawRightString(left + 16.8 * cm, self.y - self.font_height, _formatPrice(el['total'])) subject = subject[1:] x = 1 for line in subject: self.canvas.drawString(left + 2.2 * cm, self.y - (x * self.line_height) - self.font_height, line) x += 1 for line in desc: self.canvas.drawString(left + 2.2 * cm, self.y - (x * self.line_height) - self.font_height, line) x += 1 odd = not odd self.y -= (need_lines * self.line_height) + self.line_padding if part.summary: need_lines = 5 if self.y - (need_lines + 1 * (self.line_height + self.line_padding)) < ( self.bottomcontent + 1 * cm): self.canvas.setFont(self.font + '-Italic', font_size) # Zwischensumme self.canvas.drawRightString(left + 14.5 * cm, self.y - self.font_height, 'Zwischensumme:') self.canvas.drawRightString(left + 16.8 * cm, self.y - self.font_height, _formatPrice(temp_sum)) # page wrap self._PageWrap() self.y = self.topcontent - font_size - self.line_padding * 3 # header self._tableHead(part) odd = True # übertrag self.canvas.setFont(self.font + '-Italic', font_size) self.canvas.drawRightString(left + 14.5 * cm, self.y - self.font_height, 'Übertrag:') self.canvas.drawRightString(left + 16.8 * cm, self.y - self.font_height, _formatPrice(temp_sum)) self.y -= self.font_height + self.line_padding self.y -= (0.3 * cm) if part.vatType == 'gross': self.canvas.setFont(self.font + '-Bold', font_size) if self.invoice.tender or not self.invoice.official: self.canvas.drawRightString(left + 14.5 * cm, self.y - self.font_height, 'Gesamtbetrag:') else: self.canvas.drawRightString(left + 14.5 * cm, self.y - self.font_height, 'Rechnungsbetrag:') self.canvas.drawRightString(left + 16.8 * cm, self.y - self.font_height, _formatPrice(part.sum)) if self.invoice.official: self.canvas.setFont(self.font, font_size) self.y -= self.line_height + self.line_padding summaries = [] vat = 0.0 if len(part.vat) == 1 and list(part.vat.keys())[0] == 0.0: self.canvas.drawString(left, self.y - self.font_height, 'Dieser Beleg wurde ohne Ausweis von MwSt erstellt.') self.y -= self.line_height else: if len(part.vat) == 1: vat = list(part.vat.keys())[0] if self.invoice.tender: summaries.append(('Im Gesamtbetrag sind %.1f%% MwSt enthalten:' % (vat * 100), _formatPrice((part.sum / (vat + 1)) * vat))) else: summaries.append(( 'Im Rechnungsbetrag sind %.1f%% MwSt enthalten:' % (vat * 100), _formatPrice((part.sum / (vat + 1)) * vat))) else: for vat, vatdata in part.vat.items(): if vat > 0: summaries.append(('%s: Im Teilbetrag von %s sind %.1f%% MwSt enthalten:' % ( vatdata[1], _formatPrice(vatdata[0]), vat * 100), _formatPrice((vatdata[0] / (vat + 1)) * vat))) else: summaries.append(('%s: Durchlaufende Posten ohne Berechnung von MwSt.' % ( vatdata[1]), 0.0)) summaries.append(('Nettobetrag:', _formatPrice(part.sum - (part.sum / (vat + 1)) * vat))) summaries.sort() for line in summaries: self.canvas.drawRightString(left + 14.5 * cm, self.y - self.font_height, line[0]) if line[1]: self.canvas.drawRightString(left + 16.8 * cm, self.y - self.font_height, line[1]) self.y -= self.line_height elif len(part.vat) == 1 and part.vatType == 'net': self.canvas.drawRightString(left + 14.5 * cm, self.y - self.font_height, 'Nettobetrag:') self.canvas.drawRightString(left + 16.8 * cm, self.y - self.font_height, _formatPrice(part.sum)) self.y -= self.line_height summaries = [] if list(part.vat.keys())[0] == 0.0: self.canvas.drawString(left, self.y - self.font_height, 'Dieser Beleg wurde ohne Ausweis von MwSt erstellt.') self.y -= self.line_height else: if len(part.vat) == 1: vat = list(part.vat.keys())[0] summaries.append(('zzgl. %.1f%% MwSt:' % (vat * 100), _formatPrice(vat * part.sum))) else: for vat, vatdata in part.vat.items(): summaries.append(('zzgl. %.1f%% MwSt (%s):' % (vat * 100, vatdata[1]), _formatPrice(vat * vatdata[0]))) summaries.sort() for line in summaries: self.canvas.drawRightString(left + 14.5 * cm, self.y - self.font_height, line[0]) self.canvas.drawRightString(left + 16.8 * cm, self.y - self.font_height, line[1]) self.y -= self.line_height sum = 0 for vat, vatdata in part.vat.items(): sum += (vat + 1) * vatdata[0] self.canvas.setFont(self.font + '-Bold', font_size) if self.invoice.tender: self.canvas.drawRightString(left + 14.5 * cm, self.y - self.font_height, 'Gesamtbetrag:') else: self.canvas.drawRightString(left + 14.5 * cm, self.y - self.font_height, 'Rechnungsbetrag:') self.canvas.drawRightString(left + 16.8 * cm, self.y - self.font_height, _formatPrice(sum)) self.canvas.setFont(self.font, font_size) self.y -= self.line_height + self.line_padding paysum = 0.0 for pay in part.payments: paysum += pay['amount'] descr = 'Zahlung' if pay['type'] == 'cash': descr = 'gegeben' elif pay['type'] == 'return': descr = 'zurück' elif pay['type'] == 'ec': descr = 'Kartenzahlung (EC)' elif pay['type'] == 'gutschein': descr = 'Einlösung Gutschein' if pay['date'] != self.invoice.date: descr += ' am %s' % (pay['date'].strftime('%d. %m. %Y')) self.canvas.drawRightString(left + 14.5 * cm, self.y - self.font_height, descr + ':') self.canvas.drawRightString(left + 16.8 * cm, self.y - self.font_height, _formatPrice(pay['amount'])) self.y -= self.line_height sum = part.sum if part.vatType == 'net': sum = 0 for vat, vatdata in part.vat.items(): sum += (vat + 1) * vatdata[0] rest = sum - paysum if part.payments and rest > 0: self.canvas.setFont(self.font + '-Bold', font_size) self.canvas.drawRightString(left + 14.5 * cm, self.y - self.font_height, 'Offener Rechnungsbetrag:') self.canvas.drawRightString(left + 16.8 * cm, self.y - self.font_height, _formatPrice(rest)) self.canvas.setFont(self.font, font_size) self.y -= self.line_height + self.line_padding self.y -= self.line_padding elif isinstance(part, InvoiceText): my_font_size = font_size + part.fontsize # Relative Schriftgröße beachten self.canvas.setFont(self.font, my_font_size) left, right = self.leftcontent, self.rightcontent firsttime = True headlines = [] if part.urgent: left += 1.5 * cm right -= 1.5 * cm if part.headline: headlines = self._splitToWidth(part.headline, right - left, self.font, my_font_size) for para in part.paragraphs: lines = self._splitToWidth(para, right - left, self.font, my_font_size) if part.urgent: need_height = len(lines) * self._lineHeight(my_font_size) if len(headlines) > 0: need_height += len(headlines) * (self._lineHeight(my_font_size) + 1) + self.line_padding self.canvas.setFillColorRGB(0.95, 0.95, 0.95) self.canvas.rect(left - 0.5 * cm, self.y - (need_height + (6 * self.line_padding)), height=need_height + (6 * self.line_padding), width=right - left + 1 * cm, fill=1, stroke=1) self.canvas.setFillColorRGB(0, 0, 0) self.y -= self.line_padding * 3 if part.headline and firsttime: firsttime = False self.canvas.setFont(self.font + '-Bold', my_font_size + 1) for line in headlines: self.canvas.drawString(left, self.y - (self.font_height + 1), line) self.y -= self._lineHeight(my_font_size) + 1 self.y -= self.line_padding self.canvas.setFont(self.font, my_font_size) for line in lines: self.canvas.drawString(left, self.y - self.font_height, line) self.y -= self._lineHeight(my_font_size) self.y -= self.line_padding * 3 elif isinstance(part, InvoiceImage): width = (part.imagedata.width / part.dpi) * inch height = width * (part.imagedata.height / part.imagedata.width) x = self.leftcontent if part.alignment == "center": x = self.leftcontent + (self.rightcontent - self.leftcontent) / 2 - width / 2 elif part.alignment == "right": x = self.rightcontent - width self.canvas.drawInlineImage(part.imagedata, x, self.y - height, width=width, height=height) self.y -= self.line_padding + height if part.caption: self.canvas.drawString(x, self.y - self.font_height, part.caption) self.y -= self._lineHeight() else: raise NotImplementedError("Cannot handle part of type %s" % type(part)) self.y -= (0.5 * cm) self.canvas.showPage() self.canvas.save() pdfdata = self.fd.getvalue() return pdfdata def InvoiceToPDF(iv): pdf = PDF(iv) return pdf.renderRechnung()