===================================== PDF generation advanced configuration ===================================== In order to redefine the PDF layout you must create a new function in the settings.py file. For this example we will call it pdf_invoice_new. Once the new function is created you can modify it to change the default PDF layout. In order to edit the settings.py file please see :ref:`How to edit settings.py file`. .. code-block:: python def footer_pagination(canvas, doc): canvas.saveState() canvas.translate(0, 0) canvas.setFont('Helvetica-Bold', 6) width, height = pagesizes.A4 canvas.drawCentredString(width / 2, cm, "Page {}".format(doc.page)) canvas.restoreState() def pdf_invoice_new( pdf_file, invoice_display_number, invoice_status, customer_details, company_details, invoice_items, invoice_totals, invoice_issue_date=None, invoice_due_date=None, text_after_invoice_items=None, invoice_title=None, invoice_author=None, invoice_creator=None, invoice_lang=None, invoice_subject=None, invoice_currency='', ): # Define paragraph styles title_style = ParagraphStyle(name='invTitleStyle', fontName='Helvetica-Bold', fontSize=16, textColor='#404040', testTransform='upper', leading=20) sub_title_style = ParagraphStyle(name='invTitleStyle', fontName='Helvetica-Bold', fontSize=8, leading=10, textColor='#404040', testTransform='upper') norm_style = ParagraphStyle(name='invNormStyle', fontName='Helvetica', textColor='#606060', fontSize=8, leading=10) norm_style_bold = ParagraphStyle(name='invNormStyle', fontName='Helvetica-Bold', textColor='#606060', fontSize=8, leading=10) totals_style_bold = ParagraphStyle(name='invNormStyle', fontName='Helvetica-Bold', textColor='#000000', fontSize=8, leading=10, alignment=enums.TA_RIGHT) cost_style = ParagraphStyle(name='invCostStyle', fontName='Helvetica', textColor='#000000', fontSize=8, leading=10, alignment=enums.TA_CENTER) norm_style_right = ParagraphStyle(name='invNormStyleRight', fontName='Helvetica', textColor='#606060', fontSize=8, leading=10, alignment=enums.TA_RIGHT) head_style = ParagraphStyle(name='headStyle', fontName='Helvetica', textColor='#ffffff', backColor='#404040', fontSize=10, leading=12) # Begin invoice pdf generation invoice_title = invoice_title or invoice_display_number invoice_author = invoice_author or 'Fleio Billing' invoice_creator = invoice_creator or 'Fleio Billing' invoice_lang = invoice_lang or 'en' invoice_subject = invoice_subject or '{} {}'.format(invoice_display_number, invoice_status) doc = SimpleDocTemplate(pdf_file, pagesize=pagesizes.A4, leftMargin=cm, rightMargin=cm, topMargin=cm, bottomMargin=cm, title=invoice_title, author=invoice_author, creator=invoice_creator, lang=invoice_lang, subject=invoice_subject) # noinspection PyListCreation pdf_story = [Spacer(1, cm)] # Add invoice display number and header pdf_story.append(Paragraph(invoice_display_number, style=title_style)) pdf_story.append(Paragraph(invoice_status, style=sub_title_style)) pdf_story.append(Spacer(1, cm / 3)) # Add customer and company info customer_paragraph = [] # adds issue and due dates if invoice_issue_date: customer_paragraph.append(Paragraph(_('Issue Date: {}').format(invoice_issue_date), norm_style)) if invoice_due_date: customer_paragraph.append(Paragraph(_('Due Date: {}').format(invoice_due_date), norm_style)) # adds customer info customer_paragraph.append(Paragraph(_('Invoiced to:'), norm_style_bold)) customer_details = customer_details or 'Customer details missing' for cinf in customer_details.splitlines(): customer_paragraph.append(Paragraph(cinf, norm_style)) # adds company info company_details = company_details or 'Company details missing' company_paragraph = [Paragraph(cinf, norm_style_right) for cinf in company_details.splitlines()] invoice_info = Table(data=[[customer_paragraph, company_paragraph]], style=[('VALIGN', (0, 0), (-1, -1), 'TOP'), ('LEFTPADDING', (0, 0), (0, 0), 0), ('RIGHTPADDING', (0, 0), (-1, -1), 0)]) pdf_story.append(invoice_info) # Add invoice items # Set some items styles first table_style = [('BACKGROUND', (0, 0), (-1, 0), '#404040'), ('ALIGN', (3, 0), (-1, -1), 'CENTER'), ('VALIGN', (3, 0), (-1, -1), 'MIDDLE'), ('TEXTCOLOR', (1, 0), (-1, 0), '#ffffff'), ('SPAN', (0, 0), (2, 0)), ('LINEAFTER', (0, 1), (-2, -len(invoice_totals) - 1), 0.1, '#707070', None, (2, 2, 2)), ('LINEBELOW', (0, 1), (-1, -len(invoice_totals) - 1), 0.1, '#707070', None, (2, 2, 2))] items_table = [] items_header = [Paragraph(_('Description'), head_style), '', '', _('Quantity'), _('Unit Price'), _('Cost')] items_table.append(items_header) last_item_num = 1 for item in invoice_items: item_description = item['description'] for option in item.get('options', []): item_description = '{}
- {}'.format(item_description, option['display']) if option.get('price', 0) > 0: item_description = '{} ({} {})'.format(item_description, option['price'], invoice_currency) items_table.append([Paragraph(item_description, norm_style), '', '', Paragraph(str(item.get('quantity', '1')), cost_style), Paragraph(str(item.get('unit_price')), cost_style), Paragraph(str(item.get('cost')), cost_style)]) table_style.append(('SPAN', (0, last_item_num), (2, last_item_num))) last_item_num += 1 # Add totals for inv_total in invoice_totals: items_table.append(['', '', '', '', Paragraph(str(inv_total['name']), totals_style_bold), Paragraph(str(inv_total['value']), cost_style)]) table_style.append(('LINEAFTER', (4, last_item_num), (-2, -1), 0.1, '#707070', None, (2, 2, 2))) table_style.append(('LINEBELOW', (4, last_item_num), (-1, -2), 0.1, '#707070', None, (2, 2, 2))) invoice_items_table = Table(data=items_table, style=table_style) pdf_story.append(invoice_items_table) if text_after_invoice_items: pdf_story.append(Paragraph(text=text_after_invoice_items, style=norm_style)) doc.build(pdf_story, onFirstPage=footer_pagination, onLaterPages=footer_pagination) After you create the function you will also have to solve dependencies, by adding the following lines at the begginning of the settings.py file: .. code-block:: python from reportlab.lib import enums, pagesizes from reportlab.lib.styles import ParagraphStyle from reportlab.lib.units import cm from reportlab.platypus import SimpleDocTemplate, Spacer, Paragraph, Table from django.utils.translation import ugettext_lazy as _ Finally, add the following line after the function that you added earlier and restart fleio, celery and uwsgi services: .. code-block:: python PDF_INVOICE_CALLABLE = pdf_invoice_new