""" BSD license - created by Massimo Di Pierro """ from __future__ import print_function from reportlab.pdfgen.canvas import Canvas from reportlab.platypus import Table from reportlab.lib.pagesizes import A4 from reportlab.lib.units import cm from decimal import Decimal import cStringIO import datetime def listify(item): if isinstance(item,basestring): item = item.split('\n') return item class PDF(object): def __init__(self, page_size=A4, font_face='Helvetica'): self.page_size = page_size self.font_face = font_face self.logo = None def format_currency(self,value): a = list(str(int(value))) for k in range(len(a)-3,0,-3): a.insert(k,',') a = ''.join(a) b = ("%.2f" % (value-int(value)))[2:] return "%s.%s" % (a,b) def draw(self, invoice, items_page=10): """ Draws the invoice """ buffer = cStringIO.StringIO() invoice_items = invoice['items'] pages = max((len(invoice_items)-2)/items_page+1,1) canvas = Canvas(buffer, pagesize=self.page_size) for page in range(pages): canvas.translate(0, 29.7 * cm) canvas.setFont(self.font_face, 10) canvas.saveState() canvas.setStrokeColorRGB(0.9, 0.5, 0.2) canvas.setFillColorRGB(0.2, 0.2, 0.2) canvas.setFont(self.font_face, 16) canvas.drawString(1 * cm, -1 * cm, invoice.get('title','')) if self.logo: canvas.drawInlineImage(self.logo, 1 * cm, -1 * cm, 250, 16) canvas.setLineWidth(4) canvas.line(0, -1.25 * cm, 21.7 * cm, -1.25 * cm) canvas.restoreState() canvas.saveState() notes = listify(invoice.get('notes','')) textobject = canvas.beginText(1 * cm, -25 * cm) for line in notes: textobject.textLine(line) canvas.drawText(textobject) textobject = canvas.beginText(18 * cm, -28 * cm) textobject.textLine('Pag.%s/%s' % (page+1,pages)) canvas.drawText(textobject) canvas.restoreState() canvas.saveState() business_details = listify(invoice.get('from','FROM:')) canvas.setFont(self.font_face, 9) textobject = canvas.beginText(13 * cm, -2.5 * cm) for line in business_details: textobject.textLine(line) canvas.drawText(textobject) canvas.restoreState() canvas.saveState() client_info = listify(invoice.get('to','TO:')) textobject = canvas.beginText(1.5 * cm, -2.5 * cm) for line in client_info: textobject.textLine(line) canvas.drawText(textobject) canvas.restoreState() textobject = canvas.beginText(1.5 * cm, -6.75 * cm) textobject.textLine(u'Invoice ID: %s' % invoice.get('id','')) textobject.textLine(u'Invoice Date: %s' % invoice.get('date',datetime.date.today())) textobject.textLine(u'Client: %s' % invoice.get('client_name','')) canvas.drawText(textobject) items = invoice_items[1:][page*items_page:(page+1)*items_page] if items: data = [invoice_items[0]] for item in items: data.append([ self.format_currency(x) if isinstance(x,float) else x for x in item]) righta = [k for k,v in enumerate(items[0]) if isinstance(v,(int,float,Decimal))] if page == pages-1: total = self.format_currency(invoice['total']) else: total = '' data.append(['']*(len(items[0])-1)+[total]) colWidths = [2.5*cm]*len(items[0]) colWidths[1] = (21.5-2.5*len(items[0]))*cm table = Table(data, colWidths=colWidths) table.setStyle([ ('FONT', (0, 0), (-1, -1), self.font_face), ('FONTSIZE', (0, 0), (-1, -1), 8), ('TEXTCOLOR', (0, 0), (-1, -1), (0.2, 0.2, 0.2)), ('GRID', (0, 0), (-1, -2), 1, (0.7, 0.7, 0.7)), ('GRID', (-1, -1), (-1, -1), 1, (0.7, 0.7, 0.7)), ('BACKGROUND', (0, 0), (-1, 0), (0.8, 0.8, 0.8)), ]+[('ALIGN',(k,0),(k,-1),'RIGHT') for k in righta]) tw, th, = table.wrapOn(canvas, 15 * cm, 19 * cm) table.drawOn(canvas, 1 * cm, -8 * cm - th) if page == pages-1: items = invoice['totals'][1:] if items: data = [invoice['totals'][0]] for item in items: data.append([ self.format_currency(x) if isinstance(x,float) else x for x in item]) righta = [k for k,v in enumerate(items[0]) if isinstance(v,(int,float,Decimal))] total = self.format_currency(invoice['total']) data.append(['']*(len(items[0])-1)+[total]) colWidths = [2.5*cm]*len(items[0]) colWidths[1] = (21.5-2.5*len(items[0]))*cm table = Table(data, colWidths=colWidths) table.setStyle([ ('FONT', (0, 0), (-1, -1), self.font_face), ('FONTSIZE', (0, 0), (-1, -1), 8), ('TEXTCOLOR', (0, 0), (-1, -1), (0.2, 0.2, 0.2)), ('GRID', (0, 0), (-1, -2), 1, (0.7, 0.7, 0.7)), ('GRID', (-1, -1), (-1, -1), 1, (0.7, 0.7, 0.7)), ('BACKGROUND', (0, 0), (-1, 0), (0.8, 0.8, 0.8)), ]+[('ALIGN',(k,0),(k,-1),'RIGHT') for k in righta]) tw, th, = table.wrapOn(canvas, 15 * cm, 19 * cm) table.drawOn(canvas, 1 * cm, -18 * cm - th) canvas.showPage() canvas.save() return buffer.getvalue() if __name__=='__main__': invoice = { 'title': 'Invoice - web2py.com', 'id': '00001', 'date': '10/10/2013', 'client_name': 'Nobody', 'from': 'FROM:\nweb2py.com\nWabash ave\nChicago', 'to': 'TO:\nNobody\nHis address', 'notes': 'no comment!', 'total': 650.00, 'items': [ ['Codice','Desc','Quantity','Unit price','Total']]+[ ['000001','Chair',2,10.0,20.0] for k in range(30)], 'totals': [ ['Codice','Desc','Total']]+[ ['000001','Chairs',600.0], ['','Tax',50.0]], } print(PDF().draw(invoice,items_page=20))