diff --git a/VERSION b/VERSION index 200fef6a..c04f9964 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.6.0-development+timestamp.2013.08.21.04.38.11 +Version 2.6.0-development+timestamp.2013.08.21.05.07.02 diff --git a/gluon/contrib/pdfinvoice.pdf b/gluon/contrib/pdfinvoice.pdf new file mode 100644 index 00000000..9861d796 --- /dev/null +++ b/gluon/contrib/pdfinvoice.pdf @@ -0,0 +1,161 @@ +""" +BSD license - created by Massimo Di Pierro +""" +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)