git.schokokeks.org
Repositories
Help
Report an Issue
invoice.git
Code
Commits
Branches
Tags
Suche
Strukturansicht:
6dc3771
Branches
Tags
factur-x_localdata
master
invoice.git
src
rechnung
Invoice
pdf.py
Struktur verändern (broken!)
Bernd Wurst
commited
6dc3771
at 2008-01-23 17:59:01
pdf.py
Blame
History
Raw
# -* coding: utf8 *- from InvoiceObjects import * import re # reportlab imports from reportlab.lib.units import cm from reportlab.lib.pagesizes import A4 from reportlab.pdfbase.ttfonts import TTFont, TTFontFace, TTFontFile, TTFOpenFile, \ TTFontParser, TTFontMaker, TTFError, \ parse_utf8, makeToUnicodeCMap, \ FF_SYMBOLIC, FF_NONSYMBOLIC, \ calcChecksum from reportlab.pdfbase import pdfmetrics from reportlab.pdfgen import canvas as Canvas fontpath_vera = '/usr/share/fonts/ttf-bitstream-vera/' def _formatPrice(price, symbol='€'): '''_formatPrice(price, symbol='€'): Gets a floating point value and returns a formatted price, suffixed by 'symbol'. ''' s = ("%.2f" % price).replace('.', ',') pat = re.compile(r'([0-9])([0-9]{3}[.,])') while pat.search(s): s = pat.sub(r'\1.\2', s) return s+' '+symbol def _niceCount(value): '''_niceCount(value): Returns a tuple (integer , decimals) where decimals can be None''' if type(value) == int: return ('%i' % value, None) if round(value, 2) == int(value): return ('%i' % int(value), None) s = '%.2f' % value (integer, decimals) = s.split('.', 1) if decimals[-1] == '0': decimals = decimals[:-1] return (integer, decimals) def _registerFonts(): pdfmetrics.registerFont(TTFont("Vera", fontpath_vera + "Vera.ttf")) pdfmetrics.registerFont(TTFont("Vera-Bold", fontpath_vera + "VeraBd.ttf")) pdfmetrics.registerFont(TTFont("Vera-Oblique", fontpath_vera + "VeraIt.ttf")) pdfmetrics.registerFont(TTFont("Vera-BoldOblique", fontpath_vera + "VeraBI.ttf")) def _splitToWidth(canvas, 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 canvas.stringWidth(' '.join(mywords) + ' ' + words[0], font, size) <= width: mywords.append(words[0]) del words[0] lines.append(' '.join(mywords)) return lines def _PageMarkers(canvas): """Setzt Falzmarken""" from reportlab.lib.units import cm canvas.setStrokeColorRGB(0,0,0) canvas.setLineWidth(0.01*cm) 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 _PageWrap(canvas): '''Seitenumbruch''' canvas.showPage() canvas.translate(0, A4[1]) _PageMarkers(canvas) def InvoiceToPDF(iv): _registerFonts() from StringIO import StringIO fd = StringIO() canvas = Canvas.Canvas(fd, pagesize=A4) (width, height) = A4 font = 'Vera' canvas.setFont(font, 12) # Set marker to top. canvas.translate(0, A4[1]) # Set default font size default_font_size = 9 # set margins topmargin = 2*cm bottommargin = 2.5*cm leftmargin = 2*cm rightmargin = 2*cm num_pages = 1 topcontent = -topmargin leftcontent = leftmargin rightcontent = A4[0] - rightmargin bottomcontent = -(A4[1] - bottommargin) rightcolumn = 13*cm # Waehrungssysmbol symbol = '€' y = topcontent font_size = default_font_size font_height = 0.35*cm line_padding = 0.1*cm line_height = font_height+0.1*cm _PageMarkers(canvas) def _partHeight(part): height = 0 if type(part) == InvoiceText: left, right = leftcontent, rightcontent if part.urgent: left += 1.5*cm right -= 1.5*cm height += len(part.paragraphs) * 3 * line_padding if part.headline: height += (len(_splitToWidth(canvas, part.headline, right-left, font+'-Bold', default_font_size+1)) * line_height) + line_padding for para in part.paragraphs: height += (len(_splitToWidth(canvas, para, right-left, font, default_font_size)) * line_height) + line_padding elif type(part) == InvoiceTable: ## FIXME: Das ist dreckig height = len(part.entries) * 1.1*cm height += 3*cm return height def _Footer(): canvas.line(leftcontent, bottomcontent, rightcontent, bottomcontent) canvas.setFont(font, 8) canvas.drawCentredString(leftcontent+((rightcontent-leftcontent)/2), bottomcontent-10, 'schokokeks.org GbR · Bernd Wurst / Johannes Böck · http://www.schokokeks.org/') canvas.drawCentredString(leftcontent+((rightcontent-leftcontent)/2), bottomcontent-20, 'Steuernummer: 51072/01109 (FA Backnang) · USt-ID: DE255720588') canvas.drawCentredString(leftcontent+((rightcontent-leftcontent)/2), bottomcontent-30, 'Bankverbindung: Volksbank Backnang, BLZ 602 911 20, Konto Nr. 671279 017') canvas.drawCentredString(leftcontent+((rightcontent-leftcontent)/2), bottomcontent-40, 'IBAN: DE78602911200671279017, BIC: GENODES1VBK') addy_width = 8.5*cm addy_height = 5.0*cm font_size = 8 x = 2.0 * cm y = -4.8 * cm - font_size - 1 canvas.setFont(font, font_size) canvas.drawString(x, y+0.1*cm, ' schokokeks.org - Köchersberg 25 - 71540 Murrhardt') canvas.line(x, y, x + (8.5 * cm), y) y = y - font_size - 3 font_size = 11 x += 0.5*cm y -= 0.5*cm canvas.setFont(font, font_size) for line in iv.addresslines: canvas.drawString(x, y, line) y -= line_height font_size = default_font_size y = topcontent canvas.drawInlineImage("logo.png", rightcolumn, topcontent-(3*cm), width=4.08*cm, height=3*cm) y -= (3.5*cm) canvas.setFont(font+"-Bold", font_size) #canvas.drawString(rightcolumn, y, "schokokeks.org Webhosting") #y -= (font_size + 5 + 0.2*cm) canvas.drawString(rightcolumn, y, "schokokeks.org GbR") y -= (font_size + 5) canvas.setFont(font, font_size) canvas.drawString(rightcolumn, y, "Bernd Wurst / Johannes Böck") y -= (font_size + 5) canvas.drawString(rightcolumn, y, "Köchersberg 25") y -= (font_size + 5) canvas.drawString(rightcolumn, y, "71540 Murrhardt") y -= (font_size + 10) canvas.drawString(rightcolumn, y, "Tel: 07192-936432") y -= (font_size + 5) canvas.drawString(rightcolumn, y, "Fax: 07192-936431") y -= (font_size + 5) canvas.drawString(rightcolumn, y, "E-Mail: root@schokokeks.org") y -= (font_size + 10) y = -9.5*cm canvas.setFont(font+'-Bold', font_size+3) if iv.tender: canvas.drawString(leftcontent, y, 'Angebot') else: canvas.drawString(leftcontent, y, 'Rechnung') if iv.tender: canvas.setFont(font, font_size) canvas.drawString(rightcolumn, y, "Erstellungsdatum:") canvas.drawRightString(rightcontent, y, "%s" % iv.date.strftime('%d. %m. %Y')) y -= (font_size + 0.1*cm) else: canvas.setFont(font+'-Bold', font_size) canvas.drawString(rightcolumn, y, "Bei Fragen bitte immer angeben:") y -= (font_size + 0.2*cm) canvas.setFont(font, font_size) canvas.drawString(rightcolumn, y, "Rechnungsdatum:") canvas.drawRightString(rightcontent, y, "%s" % iv.date.strftime('%d. %m. %Y')) y -= (font_size + 0.1*cm) canvas.drawString(rightcolumn, y, "Rechnungsnummer:") canvas.drawRightString(rightcontent, y, "%i" % iv.id) y -= (font_size + 0.1*cm) if iv.customerno: canvas.drawString(rightcolumn, y, "Kundennummer:") canvas.drawRightString(rightcontent, y, "%s" % iv.customerno) y -= (font_size + 0.5*cm) canvas.setFont(font, font_size) canvas.drawString(leftcontent, y, iv.salutation) y -= font_size + 0.2*cm introText = 'hiermit stellen wir Ihnen die nachfolgend genannten Leistungen in Rechnung.' if iv.tender: introText = 'hiermit unterbreiten wir Ihnen folgendes Angebot.' intro = _splitToWidth(canvas, introText, rightcontent - leftcontent, font, font_size) for line in intro: canvas.drawString(leftcontent, y, line) y -= font_size + 0.1*cm y -= font_size + 0.1*cm font_size = default_font_size for part in iv.parts: if y - _partHeight(part) < (bottomcontent + (0.5*cm)): num_pages += 1 y = bottomcontent + (0.5*cm) canvas.setFont(font, default_font_size-2) canvas.drawRightString(rightcontent, bottomcontent + line_padding, 'Fortsetzung auf Seite %i' % num_pages) _Footer() _PageWrap(canvas) y = topcontent - font_size canvas.setFillColor((0,0,0)) canvas.setFont(font, font_size-2) canvas.drawCentredString(leftcontent + (rightcontent - leftcontent) / 2, y, '- Seite %i -' % num_pages) y -= line_padding*3 if type(part) == InvoiceTable: left = leftcontent right = rightcontent top = topcontent bottom = bottomcontent canvas.setFont(font, font_size) canvas.drawString(left+(0.1*cm), y-line_height+line_padding, 'Anz.') canvas.drawString(left+(1.6*cm), y-line_height+line_padding, 'Beschreibung') if len(part.vat) == 1: canvas.drawRightString(left+(14.3*cm), y-line_height+line_padding, 'Einzelpreis') else: canvas.drawRightString(left+(13.7*cm), y-line_height+line_padding, 'Einzelpreis') canvas.drawRightString(left+(16.8*cm), y-line_height+line_padding, 'Gesamtpreis') canvas.setLineWidth(0.01*cm) canvas.line(left, y - line_height, right, y - line_height) y -= line_height + 0.02*cm odd=True for el in part.entries: subject = [] if len(part.vat) == 1: subject = _splitToWidth(canvas, el['subject'], 10.3*cm, font, font_size) else: subject = _splitToWidth(canvas, el['subject'], 9.3*cm, font, font_size) desc = [] if 'desc' in el and el['desc'] != '': desc = _splitToWidth(canvas, el['desc'], 14.5*cm, font, font_size) # draw the background if not odd: canvas.setFillColorRGB(0.9, 0.9, 0.9) else: canvas.setFillColorRGB(1, 1, 1) need_lines = len(subject) + len(desc) canvas.rect(left, y - (need_lines*line_height)-(2*line_padding), height = (need_lines*line_height)+(2*line_padding), width = right-left, fill=1, stroke=0) canvas.setFillColorRGB(0, 0, 0) y -= line_padding (integer, decimals) = _niceCount(el['count']) canvas.drawRightString(left+0.8*cm, y-font_height, integer) if decimals: canvas.drawString(left+0.8*cm, y-font_height, ',%s' % decimals) if len(part.vat) == 1: canvas.drawString(left+1.7*cm, y-font_height, subject[0]) canvas.drawRightString(left+14.3*cm, y-font_height, _formatPrice(el['price'])) if el['tender']: canvas.drawRightString(left+16.8*cm, y-font_height, 'eventual') else: canvas.drawRightString(left+16.8*cm, y-font_height, _formatPrice(el['total'])) subject = subject[1:] x = 1 for line in subject: canvas.drawString(left+1.7*cm, y-(x * line_height)-font_height, line) x += 1 for line in desc: canvas.drawString(left+1.7*cm, y-(x * line_height)-font_height, line) x += 1 else: canvas.drawString(left+1.7*cm, y-font_height, subject[0]) canvas.drawRightString(left+13.3*cm, y-font_height, _formatPrice(el['price'])) canvas.drawString(left+13.7*cm, y-font_height, str(part.vat[el['vat']][1])) if el['tender']: canvas.drawRightString(left+16.8*cm, y-font_height, 'eventual') else: canvas.drawRightString(left+16.8*cm, y-font_height, _formatPrice(el['total'])) subject = subject[1:] x = 1 for line in subject: canvas.drawString(left+1.7*cm, y-(x * line_height)-font_height, line) x += 1 for line in desc: canvas.drawString(left+1.7*cm, y-(x * line_height)-font_height, line) x += 1 odd = not odd y -= (need_lines * line_height) + line_padding if part.summary: y -= (0.3*cm) if part.vatType == 'gross': canvas.setFont(font+'-Bold', font_size) if iv.tender: canvas.drawRightString(left + 14.5*cm, y-font_height, 'Gesamtbetrag:') else: canvas.drawRightString(left + 14.5*cm, y-font_height, 'Rechnungsbetrag:') canvas.drawRightString(left + 16.8*cm, y-font_height, _formatPrice(part.sum)) canvas.setFont(font, font_size) y -= line_height + line_padding summaries = [] if len(part.vat) == 1: vat = part.vat.keys()[0] if iv.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.iteritems(): summaries.append('%s: Im Teilbetrag von %s sind %.1f%% MwSt enthalten:' % (vatdata[1], _formatPrice(vatdata[0]), vat*100), _formatPrice((vatdata[0]/(vat+1))*vat)) summaries.sort() for line in summaries: canvas.drawRightString(left + 14.5*cm, y-font_height, line[0]) canvas.drawRightString(left + 16.8*cm, y-font_height, line[1]) y -= line_height else: canvas.drawRightString(left + 14.5*cm, y-font_height, 'Nettobetrag:') canvas.drawRightString(left + 16.8*cm, y-font_height, _formatPrice(part.sum)) y -= line_height summaries = [] if len(part.vat) == 1: vat = part.vat.keys()[0] summaries.append(('zzgl. %.1f%% MwSt:' % (vat*100), _formatPrice(vat*part.sum))) else: for vat, vatdata in part.vat.iteritems(): summaries.append(('zzgl. %.1f%% MwSt (%s):' % (vat*100, vatdata[1]), _formatPrice(vat*vatdata[0]))) summaries.sort() for line in summaries: canvas.drawRightString(left + 14.5*cm, y-font_height, line[0]) canvas.drawRightString(left + 16.8*cm, y-font_height, line[1]) y -= line_height sum = 0 for vat, vatdata in part.vat.iteritems(): sum += (vat+1)*vatdata[0] canvas.setFont(font+'-Bold', font_size) if iv.tender: canvas.drawRightString(left + 14.5*cm, y-font_height, 'Gesamtbetrag:') else: canvas.drawRightString(left + 14.5*cm, y-font_height, 'Rechnungsbetrag:') canvas.drawRightString(left + 16.8*cm, y-font_height, _formatPrice(sum)) canvas.setFont(font, font_size) y -= line_height + line_padding elif type(part) == InvoiceText: my_font_size = font_size canvas.setFont(font, my_font_size) left, right = leftcontent, rightcontent firsttime = True headlines = [] if part.urgent: left += 1.5*cm right -= 1.5*cm if part.headline: headlines = _splitToWidth(canvas, part.headline, right-left, font, my_font_size) for para in part.paragraphs: lines = _splitToWidth(canvas, para, right-left, font, my_font_size) if part.urgent: need_height = len(lines) * line_height if len(headlines) > 0: need_height += len(headlines) * (line_height + 1) + line_padding canvas.setFillColorRGB(0.95, 0.95, 0.95) canvas.rect(left-0.5*cm, y - (need_height+(6*line_padding)), height = need_height+(6*line_padding), width = right-left+1*cm, fill=1, stroke=1) canvas.setFillColorRGB(0, 0, 0) y -= line_padding*3 if part.headline and firsttime: firsttime = False canvas.setFont(font+'-Bold', my_font_size+1) for line in headlines: canvas.drawString(left, y-(font_height+1), line) y -= line_height + 1 y -= line_padding canvas.setFont(font, my_font_size) for line in lines: canvas.drawString(left, y-font_height, line) y -= line_height y -= line_padding*3 left, right = leftcontent, rightcontent else: raise NotImplementedError("Cannot handle part of type %s" % type(part)) y -= (0.5*cm) _Footer() canvas.showPage() canvas.save() pdfdata = fd.getvalue() return pdfdata ####################################### ''' for el in invoiceTable.entries: if len(invoiceTable.vat) == 1: subject = _breakLine(el['subject'], width=43) ret.append(u'%5.2f %-43s %10s %10s' % (el['count'], subject[0], format_price(el['price']), format_price(el['total']))) for i in range(1,len(subject)): ret.append(u' %s' % subject[i]) else: subject = _breakLine(el['subject'], width=41) ret.append(u'%5.2f %-41s %10s %s %10s' % (el['count'], subject[0], format_price(el['price']), invoiceTable.vat[el['vat']][1], format_price(el['total']))) for i in range(1,len(subject)): ret.append(u' %s' % subject[i]) if 'desc' in el and el['desc']: desc = _breakLine(el['desc'], 43) for line in desc: ret.append(u' %s' % line) ret.append('-'*72) if invoiceTable.vatType == 'gross': ret.append((u'Rechnungsbetrag: %11s' % format_price(invoiceTable.sum)).rjust(72)) ret.append('') summaries = [] if len(invoiceTable.vat) == 1: vat = invoiceTable.vat.keys()[0] summaries.append(u' Im Rechnungsbetrag sind %.1f%% MwSt enthalten (%s)' % (vat*100, format_price((invoiceTable.sum/(vat+1))*vat))) else: for vat, vatdata in invoiceTable.vat.iteritems(): summaries.append(u' %s: Im Teilbetrag von %s sind %.1f%% MwSt enthalten (%s)' % (vatdata[1], format_price(vatdata[0]), vat*100, format_price((vatdata[0]/(vat+1))*vat))) summaries.sort() for line in summaries: ret.append(line) else: ret.append((u'Nettobetrag: %11s' % format_price(invoiceTable.sum)).rjust(72)) summaries = [] if len(invoiceTable.vat) == 1: vat = invoiceTable.vat.keys()[0] summaries.append((u'zzgl. %.1f%% MwSt: %11s' % (vat*100, format_price(vat*invoiceTable.sum))).rjust(72)) else: for vat, vatdata in invoiceTable.vat.iteritems(): summaries.append((u'zzgl. %4.1f%% MwSt (%s): %11s' % (vat*100, vatdata[1], format_price(vat*vatdata[0]))).rjust(72)) summaries.sort() for line in summaries: ret.append(line) sum = 0 for vat, vatdata in invoiceTable.vat.iteritems(): sum += (vat+1)*vatdata[0] ret.append((u'Rechnungsbetrag: %11s' % format_price(sum)).rjust(72)) return ('\n'.join(ret)).encode('utf-8') '''