Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Expand
titleTemplate details

You need to do three steps:

  1. Upload static resource

  2. Create Apex Class + Test class

  3. Create Visualforce page

Upload the following static resource with the name ‘invoice’

View file
nameinvoice.zip

classClass Ctrl_InvoiceLayout:

Code Block
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.getSubscription25LogoIdgetLogoId();
    }

    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 OrderItemOrderItems
                )
                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);
        }
    }
}

Test Class Test_Ctrl_InvoiceLayout:

Code Block
@isTest
private class Test_Ctrl_InvoiceLayout {
    @testSetup static void setup(){
        String entity = 'GoMeddo Subscription Management';

        Subscription25__Administration__c admin = new Subscription25__Administration__c(
                Subscription25__Billing_Email_Address__c = 's25@test.com',
                Subscription25__Billing_Name__c = entity,
                Subscription25__Billing_Street__c = 'teststraat',
                Subscription25__Billing_Postal_Code__c = '1234ab',
                Subscription25__Billing_City__c = 'Amsterdam',
                Subscription25__Billing_Country__c = 'Netherlands',
                Subscription25__Bank__c = 'Test Bank',
                Subscription25__BIC__c = 'test bic',
                Subscription25__IBAN__c = 'test iban',
                Subscription25__VAT_Number__c = '21',
                Subscription25__Chamber_Of_Commerce_Number__c = 'test cocn',
                Subscription25__Website__c = 'www.test.com'
        );
        admin.Name = entity;
        admin.Subscription25__Invoice_Number_Prefix__c = '123';
        Database.insert(admin);

        Account acc = new Account();
        acc.Name = 'Test Account';
        acc.BillingStreet = 'Hoogte Kadijk 38-1';
        acc.BillingPostalCode = '1018BM';
        acc.BillingCity = 'Amsterdam';
        acc.BillingCountry = 'Netherlands';
        acc.ShippingStreet = 'Hoogte Kadijk 38-1';
        acc.ShippingPostalCode = '1018BM';
        acc.ShippingCity = 'Amsterdam';
        acc.ShippingCountry = 'Netherlands';
        Database.insert(acc);

        Contact con = new Contact();
        con.LastName = 'van Test';
        con.FirstName = 'Testje';
        con.Email = 'test@test.com';
        Database.insert(con);

        Product2 prod = new Product2(); 
        prod.Name = 'Test Product';
        Database.insert(prod);

        PricebookEntry pbe = new PricebookEntry();
        pbe.Pricebook2Id = Test.getStandardPricebookId();
        pbe.Product2Id = prod.Id;
        pbe.UnitPrice = 1;
        Database.insert(pbe);

        Subscription25__Invoice__c i = new Subscription25__Invoice__c();
        i.Subscription25__Account__c = acc.Id;
        i.Subscription25__Administration__c = admin.Id;
        i.Subscription25__Invoice_Date__c = Date.today();
        i.Subscription25__Description__c = 'invoice description';
        i.Subscription25__Purchase_Order_Number__c = '1234';
        i.Subscription25__Billing_Country__c = 'NLD';
        Database.insert(i);


        Subscription25__VATRate__c vatRate = new Subscription25__VATRate__c();
        vatRate.Subscription25__Active__c = true;
        vatRate.Subscription25__Default__c = true;
        vatRate.Subscription25__VAT_Percentage__c = 19;
        Database.insert(vatRate);

        Subscription25__VAT_Code__c vatCode = new Subscription25__VAT_Code__c();
        vatCode.Subscription25__Administration__c = admin.Id;
        vatCode.Subscription25__VATRate__c = vatRate.Id;
        vatCode.Subscription25__VAT_Code__c = 'VH';
        Database.insert(vatCode);

        Subscription25__Administration_Product__c ap = new Subscription25__Administration_Product__c();
        ap.Subscription25__Administration__c = admin.id;
        ap.Subscription25__Product__c = prod.Id;
        ap.Subscription25__VATRate__c = vatRate.Id;
        ap.Subscription25__Ledger_Account__c = '1000';
        Database.insert(ap);

        Subscription25__Debtor_Number__c dbNmbr = new Subscription25__Debtor_Number__c();
        dbNmbr.Subscription25__Administration__c = admin.Id;
        dbNmbr.Subscription25__Debtor_Number__c = '123';
        dbNmbr.Subscription25__Account__c = acc.Id;
        Database.insert(dbNmbr);        

        Order ord = new Order();
        ord.AccountId = acc.Id;
        ord.Subscription25__Administration__c = admin.Id;
        ord.Pricebook2Id = Test.getStandardPricebookId();
        ord.status = 'draft';
        ord.Subscription25__Invoice__c = i.Id;
        ord.EffectiveDate = Date.today();
        Database.insert(ord);

        OrderItem ordItem = new OrderItem();
        ordItem.UnitPrice = 12;
        ordItem.Quantity = 1;
        ordItem.OrderId = ord.Id;
        ordItem.Product2Id = prod.Id;
        ordItem.Subscription25__Product__c = prod.Id;
        ordItem.Subscription25__VAT_Code__c = 'VH';
        ordItem.Subscription25__VAT_Percentage__c = 12;
        Database.insert(ordItem);

        
    }

    @IsTest
    static void test_constructor(){

        PageReference pageRef = Page.Invoice; //name of visualforce page
        Test.setCurrentPage(pageRef);
        ApexPages.StandardController sc = new ApexPages.StandardController([
            SELECT Id, Subscription25__Account__c,Subscription25__Administration__c,Subscription25__Invoice_Date__c,
                Subscription25__Description__c,Subscription25__Purchase_Order_Number__c,Subscription25__Billing_Country__c 
            FROM Subscription25__Invoice__c 
            LIMIT 1
        ]);

        Ctrl_InvoiceLayout ctrl = new Ctrl_InvoiceLayout(sc);
    }

}

Visualforce Invoice:

Code Block
<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>

...