Skip to main content
Skip table of contents

How to create a custom invoice layout

Default template

GoMeddo Subscription Management provides you want a standard layout which has limited customisation options. For now, you can:

  • Upload your logo in the administration

  • Upload your footer image in the administration

  • Change the terms and condition URL

You need to upload a file to the attachments of the Administration, that is prefixed with Logo_ or Footer_ so GoMeddo Subscription Management will know which images to capture.

The layout of the default template is as follows:

Custom template

To create a custom Invoice Layout you need to create a visualforce page that is rendered as a PDF. This page needs to have the GoMeddo Subscription Management Invoice object as it standardController. You can extend this with a custom class to get additional functionalities in the pdf.

CODE
<apex:page standardController="Subscription25__Invoice__c" renderAs="pdf" sidebar="false" showHeader="false" applyBodyTag="false">
  Invoice Date: {!Subscription25__Invoice__c.Subscription25__Invoice_Date__c}  
  etc..
</apex:page>

To use this template you must create an “Invoice template record” in GoMeddo Subscription Management and assign it to the administrations in which you want to use this template. This allows you to create different layouts for different administrations.

  • The Name of the Invoice Layout is your reference to this record.

  • The page name is the API name of your VisualforcePage. Don’t forget to add the c__ before the name.

  • One record can be the fallback record which will be used if there is no layout assigned to the administration.

It is important to start the Page name with c__ to indicate to Salesforce that this is a custom namespace visualforce page. The full name of the item will be c__<VisualForceApiName>.

On your administration, you should have a related list called Administration Invoice Layouts in which you should create a record to link this template to that administration.

You can also use the following template

Template details

You need to do three steps:

  1. Upload static resource

  2. Create Apex Class

  3. Create Visualforce page

Upload the following static resource with the name ‘invoice’

invoice.zip

class:

CODE
public with sharing class Ctrl_InvoiceLayout {

    private Subscription25__Invoice__c invoice;
    public InvoiceItem[] items {get; private set;}

    public Id companyLogoId {get; private set;}

    public Decimal sum {get; private set;}
    public Decimal total {get; private set;}
    public Decimal taxAmount {get; private set;}

    public Boolean hasICP {get; private set;}

    public Ctrl_InvoiceLayout(ApexPages.StandardController stdController) {
        this.invoice = (Subscription25__Invoice__c)stdController.getRecord();

        List<Order> orders = this.getOrders();
        this.items = new InvoiceItem[]{};
        this.hasICP = false;
        for (Order order : orders) {
            for (OrderItem item : order.OrderItems) {
                this.items.add(new InvoiceItem(item));
                this.hasICP = this.hasICP || item.Subscription25__Use_ICP__c;
            }
        }

        this.taxAmount = 0;
        this.sum = 0;
        for (InvoiceItem item : this.items) {
            this.sum += item.price * item.quantity;
            this.taxAmount += item.price * item.quantity * item.tax / 100;
        }
        this.sum = Ctrl_InvoiceLayout.format(this.sum);
        this.taxAmount = Ctrl_InvoiceLayout.format(this.taxAmount);
        this.total = Ctrl_InvoiceLayout.format(this.sum + this.taxAmount);

        //try to load an attachment of the administration that starts with logo, if present, use that as a logo, otherwise, fall back
        //to the company logo as defined in the custom setting
        List<Attachment> atts = this.getAttachments();
        this.companyLogoId = atts.size() > 0 ? atts.get(0).Id : Ctrl_InvoiceLayout.getLogoId();
    }

    private List<Attachment> getAttachments() {
        Id adminId = this.invoice.Subscription25__Administration__c;
        String query = 'SELECT Name FROM Attachment WHERE ParentId = :adminId AND Name LIKE \'Logo%\'';
        return Database.query(query);
    }

    private List<Order> getOrders() {
        Id invoiceId = this.invoice.Id;
        return [
            SELECT Name, AccountId, Account.Name, 
                Subscription25__Reseller_Customer__c, Subscription25__Reseller_Customer__r.Name, 
                Subscription25__Invoice__r.Subscription25__Account__r.Name,
                (
                    SELECT Id, Subscription25__VAT_Percentage__c, Quantity,
                        UnitPrice, Description, Subscription25__Use_ICP__c,
                        Subscription25__Hide_VAT_On_Invoice__c, Subscription25__Product__c, Subscription25__Product__r.Name,
                        OrderId, Order.Name, Order.Id, Order.AccountId, Order.Account.Name,
                        Order.Subscription25__Reseller_Customer__c, Order.Subscription25__Reseller_Customer__r.Name,
                        Order.Subscription25__Invoice__c, Order.Subscription25__Invoice__r.Subscription25__Account__c, Order.Subscription25__Invoice__r.Subscription25__Account__r.Name
                    FROM OrderItems
                )
                FROM Order
                WHERE Subscription25__Invoice__c = :invoiceId
        ];
    }

    private static Decimal format(Decimal amount) {
        return amount.setScale(2, RoundingMode.HALF_UP);
    }

    private static Id getLogoId(){
        String query = 'SELECT Id FROM Document WHERE DeveloperName LIKE \'%Subscription25_Logo\' LIMIT 1';
        List<Document> docs = Database.query(query);
        return docs.size() > 0 ? docs[0].Id : null;
    }


    private class InvoiceItem {
        public Decimal quantity {get; private set;}
        public String accountLabel {get; private set;} //used for resellers and bill to parent
        public String label {get; private set;}
        public Decimal price {get; private set;}
        public Decimal tax {get; private set;}
        public String description {get; private set;}

        public InvoiceItem(OrderItem oi) {
            this.quantity = oi.Quantity;
            this.label = oi.Subscription25__Product__r.Name;
            this.price = oi.UnitPrice;
            this.tax = oi.Subscription25__VAT_Percentage__c;
            this.description = oi.Description;

            if(oi.Order.Subscription25__Reseller_Customer__c != null){
                this.accountLabel = oi.Order.Subscription25__Reseller_Customer__r.Name;
            }
            if(oi.Order.AccountId != oi.Order.Subscription25__Invoice__r.Subscription25__Account__c){
                this.accountLabel = oi.Order.Account.Name;
            }
        }

        public Decimal getTotal() {
            Decimal total = this.price * this.quantity;
            return Ctrl_InvoiceLayout.format(total);
        }
    }
}

Visualforce:

CODE
<apex:page standardController="Subscription25__Invoice__c" extensions="Ctrl_InvoiceLayout" renderAs="pdf" sidebar="false" showHeader="false" applyBodyTag="false">
    <head>
    <link media="print" rel="stylesheet" type="text/css" href="{!URLFOR($Resource.invoice, 'css/invoice.css')}" />
    </head>
    <body>
        <div class="header">
            <apex:image value="/servlet/servlet.FileDownload?file={!companyLogoId}" styleClass="logo"/>
        </div>
        <div class="header">
            <div class="logoContainer">
                <apex:image value="/servlet/servlet.FileDownload?file={!companyLogoId}" styleClass="logo" />
            </div>
            <table class="invoiceRulesHeader">
                <thead>
                    <tr>
                        <th class="number">Quantity</th>
                        <th class="description">Description</th>
                        <th class="price right">Price</th>
                        <th class="total right">Total</th>
                        <th class="vat right">VAT</th>
                    </tr>
                </thead>
            </table>
        </div>
        <div class="footer">
            <div class="container">
                <ul>
                    <li>
                        <apex:outputField value="{!Subscription25__Invoice__c.Subscription25__Administration__r.Subscription25__Billing_Name__c}" />
                    </li>
                    <li>
                        <apex:outputText value="{!Subscription25__Invoice__c.Subscription25__Administration__r.Subscription25__Billing_Street__c}" />
                    </li>
                    <li>
                        <apex:outputText value="{!Subscription25__Invoice__c.Subscription25__Administration__r.Subscription25__Billing_Postal_Code__c} {!Subscription25__Invoice__c.Subscription25__Administration__r.Subscription25__Billing_City__c}" />
                    </li>
                    <li class="last">
                        <apex:outputText value="{!Subscription25__Invoice__c.Subscription25__Administration__r.Subscription25__Billing_Country__c}" />
                    </li>
                </ul>
                <ul>
                    <li>
                        <apex:outputText value="VAT {!Subscription25__Invoice__c.Subscription25__Administration__r.Subscription25__VAT_Number__c}" />
                    </li>
                    <li>
                        <apex:outputText value="Bank {!Subscription25__Invoice__c.Subscription25__Administration__r.Subscription25__Bank__c}" />
                    </li>
                    <li>
                        <apex:outputText value="IBAN {!Subscription25__Invoice__c.Subscription25__Administration__r.Subscription25__IBAN__c}" />
                    </li>
                    <li class="last">
                        <apex:outputText value="BIC_Swift {!Subscription25__Invoice__c.Subscription25__Administration__r.Subscription25__BIC__c}" />
                    </li>
                </ul>
            </div>
            <div class="pageNumbers">Page <span class="pagenumber"/> Of <span class="pagecount"/></div>
        </div>
        <div class="container">
            <div class="invoicevat">
                <apex:outputText value="INVOICE" />
            </div>
            <table class="contactDetails">
                <tr>
                    <td class="contactName"><apex:outputText value="{!Subscription25__Invoice__c.Subscription25__Account__r.Name}" /></td>
                </tr>
                <apex:outputPanel layout="none" rendered="true">
                    <tr>
                        <td>
                            <apex:outputText value="Attn {!Subscription25__Invoice__c.Subscription25__Contact_Person__r.Name}" rendered="{!Subscription25__Invoice__c.Subscription25__Contact_Person__c != null}"/>
                        </td>
                    </tr>
                </apex:outputPanel>
                <tr>
                    <td><apex:outputText value="{!Subscription25__Invoice__c.Subscription25__Billing_Street__c}" /></td>
                </tr>
                <tr>
                    <td><apex:outputText value="{!Subscription25__Invoice__c.Subscription25__Billing_Postal_Code__c} {!Subscription25__Invoice__c.Subscription25__Billing_City__c}" /></td>
                </tr>
                <tr>
                    <td><apex:outputText value="{!Subscription25__Invoice__c.Subscription25__Billing_Country__c}" /></td>
                </tr>
                <tr>
                    <td><apex:outputText value="{!Subscription25__Invoice__c.Subscription25__VAT_Number__c}" /></td>
                </tr>
            </table>

            <table class="invoiceDetails">
                <tr>
                    <td class="leftColumn">InvoiceDate:</td>
                    <td><apex:outputField value="{!Subscription25__Invoice__c.Subscription25__Invoice_Date__c}" /></td>
                </tr>
                <tr>
                    <td>DueDate:</td>
                    <td><apex:outputField value="{!Subscription25__Invoice__c.Subscription25__Due_Date__c}" /></td>
                </tr>
                <tr>
                    <td>InvoiceNumber:</td>
                    <td><apex:outputField value="{!Subscription25__Invoice__c.Subscription25__Invoice_Number__c}" /></td>
                </tr>
            </table>
            <apex:outputPanel rendered="{!NOT(ISBLANK(Subscription25__Invoice__c.Subscription25__Description__c))}" layout="none">
                <div class="subject">
                    <apex:outputText value="Regarding: {!Subscription25__Invoice__c.Subscription25__Description__c}" />
                </div>
            </apex:outputPanel>
            <table class="invoiceRules">
                <thead>
                    <tr>
                        <th class="number">Quantity</th>
                        <th class="description">Description</th>
                        <th class="price right">Price</th>
                        <th class="total right">Total</th>
                        <th class="vat right">VAT</th>
                    </tr>
                </thead>
                <tbody>
                    <apex:repeat var="item" value="{!items}">
                        <tr>
                            <td class="number right">
                                <apex:outputText value="{0, number,###,###,##0.00}">
                                    <apex:param value="{!item.quantity}" />
                                </apex:outputText>
                            </td>
                            <td class="description">
                                <div><apex:outputText value="{!item.accountLabel}" /></div>
                                <apex:outputText value="{!item.label}" />
                                <div class="subText"><apex:outputText value="{!item.description}" /></div>
                            </td>
                            <td class="price right">
                                <apex:outputText value="€{0, number,###,###,##0.00}">
                                    <apex:param value="{!item.price}" />
                                </apex:outputText>
                            </td>
                            <td class="total right">
                                <apex:outputText value="€{0, number,###,###,##0.00}">
                                    <apex:param value="{!item.total}" />
                                </apex:outputText>
                            </td>
                            <td class="vat right">
                                <apex:outputText value="{0, number,###,###,##0.00}%">
                                    <apex:param value="{!item.tax}" />
                                </apex:outputText>
                            </td>
                        </tr>
                    </apex:repeat>
                </tbody>
            </table>
            <div class="paymentDetails">
                <table class="invoiceRulesFooter">
                    <tbody>
                        <tr>
                            <td class="number"></td>
                            <td colspan="2" class="totalText">Subtotal (ExclTax)</td>
                            <td class="total right">
                                <apex:outputText value="€{0, number,###,###,##0.00}">
                                    <apex:param value="{!sum}" />
                                </apex:outputText>
                            </td>
                            <td class="vat"></td>
                        </tr>
                        <tr>
                            <td class="number"></td>
                            <td colspan="2" class="totalText">Tax</td>
                            <td class="total right">
                                <apex:outputText value="€{0, number,###,###,##0.00}">
                                    <apex:param value="{!taxAmount}" />
                                </apex:outputText>
                            </td>
                            <td class="vat"></td>
                        </tr>
                    </tbody>
                    <tfoot>
                        <tr>
                            <td class="number"></td>
                            <td colspan="2" class="totalText">Total (InclTax)</td>
                            <td class="total right">
                                <apex:outputText value="€{0, number,###,###,##0.00}">
                                    <apex:param value="{!total}" />
                                </apex:outputText>
                            </td>
                            <td class="vat"></td>
                        </tr>
                    </tfoot>
                </table>
                <apex:outputPanel styleClass="timeleyPayment" rendered="{!hasICP}">
                    ICPLawMessage
                </apex:outputPanel>
                <div class="timeleyPayment">
                    Please reference invoice number <strong>{!Subscription25__Invoice__c.Subscription25__Invoice_Number__c}</strong> with your payment. We appreciate your timely payment.
                </div>
                <table class="paymentInfo">
                    <tr>
                        <td class="first">Wire transfer to:</td>
                        <td></td>
                    </tr>
                    <tr>
                        <td>Bank Name:</td>
                        <td><apex:outputField value="{!Subscription25__Invoice__c.Subscription25__Administration__r.Subscription25__Bank__c}" /></td>
                    </tr>
                    <tr>
                        <td>Bank Account Name:</td>
                        <td><apex:outputField value="{!Subscription25__Invoice__c.Subscription25__Administration__r.Subscription25__Billing_Name__c}" /></td>
                    </tr>
                    <tr>
                        <td>BIC Swift:</td>
                        <td><apex:outputField value="{!Subscription25__Invoice__c.Subscription25__Administration__r.Subscription25__BIC__c}" /></td>
                    </tr>
                    <tr>
                        <td>IBAN:</td>
                        <td><apex:outputField value="{!Subscription25__Invoice__c.Subscription25__Administration__r.Subscription25__IBAN__c}" /></td>
                    </tr>
                </table>
                <apex:outputPanel rendered="{!NOT(ISBLANK(Subscription25__Invoice__c.Subscription25__Foot_Note__c))}" layout="none">
                    <div class="via-email">
                        <apex:outputField value="{!Subscription25__Invoice__c.Subscription25__Foot_Note__c}" />
                    </div>
                </apex:outputPanel>
            </div>
        </div>
    </body>
    <apex:outputText rendered="none" value="Subscription25__Invoice__c.Subscription25__Administration__c}" />
</apex:page>

Next up

Now you can setup Set up Automatic Invoice Creation and E-billing

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.